Qt-关于多线程中槽函数的执行问题

概述

众所周知,Qt实现多线程的方式有两种,一种是通过子类化QObject并将该类实例化后调用QObject::moveToThread,将对象的所有函数执行放到另一个线程当中;另一种则是通过子类化QThread后重写run内的内容。当然,QtConcurrent::run不算在此内。

第一种方法中,我们可以很容易得到槽函数会在moveToThread的那个线程中执行。再这,我们着重讨论第二种办法。

QThread

通常,我们对QThread子类化后,会将需要执行的内容放在run函数中。Qt也告诉我们:**QThread实例位于实例化它的旧线程中,而不是位于调用run()的新线程中。这意味着QThread的所有队列槽函数和调用的方法都将在旧线程中执行。因此,希望在新线程中调用槽的开发人员必须使用worker对象方法;新的槽函数不应该直接实现到子类QThread中。**

1
2
3
It is important to remember that a QThread instance lives in the old thread that instantiated it, not in the new thread that calls run(). 
This means that all of QThread's queued slots and invoked methods will execute in the old thread.
Thus, a developer who wishes to invoke slots in the new thread must use the worker-object approach; new slots should not be implemented directly into a subclassed QThread.

那么有没有一种办法,让子类化QThread的类实例中的槽函数在其内部执行呢?

connect

说起槽函数,就得说起connect。这个函数在日常使用中通常只会注意前四个参数,但其第五个参数Qt::ConnectType在当前应用场景中可以说有着独到之处。

下面的三个Qt::ConnectType的值,有其独特的意义:

  1. AutoConnection
    • 默认值;
    • 如果信号在接收者所依附的线程发射,则为DirectConnection
    • 如果发射信号的线程与接受者所依附的线程不同,则为QueuedConnect
  2. DirectConnection
    • 当信号发出时,槽函数直接被调用;
    • 无论槽函数对象在哪个线程,函数调用都在信号发出者所依附线程执行;
  3. QueuedConnection
    • 当控制权回到接受者所依附线程的事件循环时,槽函数被调用;
    • 槽函数在接收者所依附线程执行;

moveToThread

说回QThreadQThread继承自QObject。我们可以从此处下手,通过moveToThread(this),将子类化后的对象通过移到本线程执行。

此时通过信号调用槽函数时,槽函数会在当前QThread子类依附线程执行。