线程依附性

一个QObject实例是具有线程依附性的,或者说它驻留在某个线程。当一个OQbject接收到队列信号(queued signal)或者投递事件(posted event),槽函数或者事件处理函数运行在对象驻留的线程中。


    注意:如果一个QObject没有线程依附性(也就是说thread()函数返回0),或者它位于没有运行事件循环的线程内,那么它就不能接收到队列信号或者投递事件。


    一个QObject默认是位于创建它的线程内。一个对象的线程依附性可以使用thread()查询,并且可以通过moveToThread()改变。


    所有的QObjects必须和它们的父类位于同一个线程。所以:

    1)如果牵涉到的两个QObject对象位于不同的线程,setParent()会失败。

    2)当一个QObject对象移动到另一个线程,它的所有子类也会自动移动。

    3)如果QObject对象有父类,moveToThread()会失败。

    4)如果QObject对象在QThread::run()函数内创建,它们不可以成为QThread对象的子类,因为QThread并不是驻留在调用QThread::run()的线程内。


    注意:一个QObject的成员变量不会自动成为它的子类。父—子关系必须通过传递指针给子类的构造函数,或者调用setParent()函数来设置。没有这一步,当moveToThread()被调用时,对象的成员变量仍旧会留在旧的线程中。


    下面是示例代码,用来验证线程依附性

/* threadaffinity.h */
#ifndef THREADAFFINITY
#define THREADAFFINITY

#include <QThread>

class Thread : public QThread
{
    Q_OBJECT

signals:
    void sendSignal();
protected:
    void run();
};

class Object : public QObject
{
    Q_OBJECT

public slots:
    void receiveSlot();
};


#endif // THREADAFFINITY


 
/* threadaffinity.cpp */
#include <QDebug>
#include <QTimer>
#include "threadaffinity.h"

void Object::receiveSlot()
{
    QTimer* timer = new QTimer;
    qDebug() << "Object::receiveSlot " << timer->thread();
    delete timer;
}

void Thread::run()
{
    QTimer* timer = new QTimer;
    qDebug() << "Thread::run " << timer->thread();
    emit sendSignal();
    delete timer;
}
 
/* main.cpp */
#include "threadaffinity.h"
#include <Qtcore/QCoreApplication>
#include <QDebug>

int main(int argc, char* argv[])
{
    QCoreApplication app(argc, argv);
    Thread thread;
    Object object;

    qDebug() << "main " << app.thread();
    qDebug() << "thread " << thread.thread();
    qDebug() << "object " << object.thread();

    QObject::connect(&thread, SIGNAL(sendSignal()), &object, SLOT(receiveSlot()));
    thread.start();

    return app.exec();
}

 
 

输出结果如下:

图


先说一下跨线程的信号和槽机制,Qt支持5种信号-槽连接类型:

       1)自动连接(默认) 如果信号在接收对象具有依附性的线程内发射,那么行为和直接连接一样。否则,行为和 队列连接一样。

       2)直接连接               如果信号被发射,槽立即被调用。槽在发射者线程内执行,并不一定在接收者线程内执 行。

       3)队列连接               当控制权返回给接收者线程的事件循环时槽被调用。槽在接收者线程内执行。

       4)阻塞队列连接        槽被调用的方式和队列连接一样,除了当前线程会阻塞直到槽返回。

       注意:在同个线程使用这种类型连接对象会造成死锁。

       5)唯一连接               行为和自动连接一样,但是只有它没有复制现有连接的时候才会进行连接。换言之,对于 同一对对象,如果相同的信号已经连接到相同的槽,那么不会进行连接,connect()返回false。


由输出结果可知,thread和object的线程依附性相同,他们隶属于地址为0x8835a8的线程,也就是main函数所在的线程。这正说明了一个QObject对象默认是位于创建它的线程内,thread和object对象正是在主线程内创建的。object对象的槽函数也属于地址为0x8835a8的线程,因为我们使用的是自动连接,而接收对象和发射信号所在的线程并没有依附性(可以通过moveToThread()改变),所以会使用队列连接,这时槽会在接收者线程执行,也就是在地址为0x8835a8的主线程执行。只有发射者才真正在自己类(Thread类)所在的线程运行。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值