QThread 事件循环

对QThread的run函数描述如下:

  • The run() implementation is for a thread what the main() entry point is for the application. All code executed in a call stack that starts in the run() function is executed by the new thread, and the thread finishes when the function returns.

Bradley T. Hughes 给出说明是: QThread 应该被看做是操作系统线程的接口或控制点,而不应该包含需要在新线程中运行的代码。需要运行的代码应该放到一个QObject的子类中,然后将该子类的对象moveToThread到新线程中。

QObject::connect的三种连接方式定义:


  1. 自动连接
  1. 这是默认设置
  2. 如果信号在接收者所依附的线程内发射,则等同于直接连接
  3. 如果发射信号的线程和接收者所依附的线程不同,则等同于队列连接
  4. 也就是说只存在下面两种情况:直接连接、队列连接
  1. 直接连接
  1. 当信号发射时,槽函数将直接被调用
  2. 无论槽函数所属对象在哪个线程,槽函数都在发射信号的线程内执行(根据该条描述,自动连接的2)是特例,正好发射信号的线程和槽函数所依附的线程是同一线程,所以也在接收者所依附的线程执行。其他情况下直接连接并不一定是在接收者所依附的线程执行)
  1. 队列连接
  1. 当控制权回到接收者所依附线程的事件循环时,槽函数被调用
  2. 槽函数在接收者所依附的线程执行


关于QThread的几个结论:

  • QThread是用来管理线程的,它所依附的线程和它管理的线程不是同一个东西;
  • QThread所依附的线程是执行QThread t(0)或QThread* pT=new QThread(0)的线程;
  • QThread管理的线程,就是run启动的线程

看下面的例子:

#include <QCoreApplication>

#include <QObject>

#include <QThread>

#include <QDebug>

class Dummy:public QObject

{

    Q_OBJECT

public:

    Dummy(){}

public slots: //槽函数

    void emitsignal()

    {

        emit sig();

    }

signals: //信号

    void sig();

};

class Thread:public QThread

{

    Q_OBJECT

public:

    Thread(QObject* parent=0):QThread (parent)

    {

        //moveToThread(this);

    }

public slots:

    void slot_main()

    {

        qDebug()<<"Thread slot_main:"<<currentThreadId();

    }

protected:

    void run()

    {

        qDebug()<<"Thread run:"<<currentThreadId();

        exec();

    }

};

#include "main.moc"

int main(int argc, char *argv[])

{

    QCoreApplication a(argc, argv);

    qDebug()<<"main Thread:"<<QThread::currentThreadId();

    Thread thread;

    Dummy dummy;

    QObject::connect(&dummy,SIGNAL(sig()),&thread,SLOT(slot_main())); //自动连接的等同于直接连接的情况,槽函数在主线程中被调用

    thread.start();

    dummy.emitsignal();

    return a.exec();

}

执行结果:

从结果可以看出:槽函数的线程和主线程是一样的。

Qt自带的例子QThread中slot和run函数共同操作的对象,都会用QMutex锁住。为什么?

因为slot和run处于不同的线程,需要线程间的同步!

如果想让槽函数slot在次线程中运行(比如它执行耗时的操作会让主线程卡住或死掉),怎么解决呢?

  1. 注意:例子中是自动连接中等同于直接连接的情况,dummy信号发射的线程和接收者QThread所依附的线程相同,都是主线程。所以槽函数会在主线程中被调用。
  2. 参考前面的结论:

将thread依附的线程改为次线程,即自动连接中等同于队列连接的情况,槽函数在thread所依附的线程执行;

这也是代码中Thread的构造函数中moveToThread(this);所做的,去掉注释后运行结果如下:

         Slot确实在thread中被执行,但这是Bradley T. Hughes强烈批判的用法。

run中信号与QThread中槽

定义一个Dummy类,在run中发射它的信号,在主线程中实例化Thread

也可以在run中发射Thread类中的信号,而不是Dummy(效果完全一样)

        

这是自动连接中等同于队列连接的情况,thread本身依附的线程是主线程,所以它的槽函数也在主线程执行。

如何解决呢(在主线程执行的问题)

  1. (方法一)前面提到了moveToThread可以用也可以解决问题。但同样是被批判的对象。
  2. (方法二)注意,这里信号是次线程发出的,对比connect的连接方式,会发现:
  1. 采用直接连接,槽函数将在次线程(信号发出的线程)执行
  2. 这个方法不太好,因为你需要处理slot和它的对象所在线程的同步。需要QMutex一类的东西slot在次线程执行,它的对象所在线程是thread所依附的线程即主线程,也就是说需要处理主线程和次线程的同步

推荐的方法

这是一个又简单又好用的方法。定义一个普通的QObject派生类,然后将其对象moveQThread中。使用信号和槽时根本不用考虑多线程的存在。也不用使用QMutex来进行同步,Qt的事件循环会自己自动处理好这个。(没太明白???)

代码示例:

#include <QCoreApplication>

#include <QObject>

#include <QThread>

#include <QDebug>

class Dummy:public QObject

{

    Q_OBJECT

public:

    Dummy(){}

public

    void emitsignal()

    {

        emit sig();

    }

signals: //信号

    void sig();

};

class Object : public QObject

{

    Q_OBJECT

public:

    Object() {}

    virtual ~Object() {}

public slots:

    void slot()

    {

        qDebug()<<"thread slot:"<<QThread::currentThreadId();

    }

};

#include "main.moc"

int main(int argc, char *argv[])

{

    QCoreApplication a(argc, argv);

    qDebug()<<"main Thread:"<<QThread::currentThreadId();

    QThread thread;

    Object obj;

    Dummy dummy;

    obj.moveToThread(&thread);

    QObject::connect(&dummy,SIGNAL(sig()),&obj,SLOT(slot()));

    thread.start();

    dummy.emitsignal();

    return a.exec();

}

执行结果:

Slot确实不在主线程中执行了

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值