connect函数的第五个参数 connect第五个参数介绍
每一个线程都有自己的事件队列与事件循环系统(exec())。
线程通过事件队列接收信号
信号在事件循环中被处理
Qt:: Connection 自动连接:默认的方式。信号发出的线程和糟的对象在一个线程的时候相当于:DirectConnection, 如果是在不同线程,则相当于QueuedConnection。
Qt::DirectConnection(是同步) 直接连接:相当于直接调用槽函数,但是当信号发出的线程和槽的对象在一个线程的时候,信号发出后,对应的槽函数将马上被调用。emit语句后的代码将在全部槽函数运行完成后被运行。在这个线程内是顺序运行、同步的。 如果信号所在线程和槽函数所在线程不是一个线程,会强制把槽函数拉到和信号所在的一样的线程来执行,并且是同步执行,这时打印的槽函数线程和信号线程ID是一个ID(为信号发送时所在线程的ID),emit后面的内容需要等到槽函数执行完毕才执行。
代码大意:创造其他线程发送信号,触发出线程中MyObject对象中的槽函数,打印线程号,观察执行时机、执行线程号的差异。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 class MyObject : public QObject{ Q_OBJECT public : explicit MyObject (QObject *parent = 0 ) ; signals: protected slots: void testSlot () ; }; void MyObject::testSlot () { qDebug () << "void MyObject::testSlot() tid = " << QThread::currentThreadId (); } class TestThread : public QThread{ Q_OBJECT protected : void run () ; public : explicit TestThread (QObject *parent = 0 ) ; signals: void testSignal () ; }; void TestThread::run () { qDebug () << "void TestThread::run() -- begin tid = " << currentThreadId (); for (int i=0 ; i<3 ; i++) { qDebug () << "void TestThread::run() i = " << i; sleep (1 ); } emit testSignal () ; exec (); qDebug () << "void TestThread::run() -- end" ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 void direct_connection () { static TestThread t; static MyObject m; QObject::connect (&t, SIGNAL (testSignal ()), &m, SLOT (testSlot ()), Qt::DirectConnection); t.start (); t.wait (5 * 1000 ); t.quit (); } int main (int argc, char *argv[]) { QCoreApplication a (argc, argv) ; qDebug () << "main() tid = " << QThread::currentThreadId (); direct_connection (); return a.exec (); }
执行结果:
1 2 3 4 5 6 7 8 9 10 main () tid = 0x2ff4 void TestThread::run () – begin tid = 0x1d98 void TestThread::run () i = 0 void TestThread::run () i = 1 void TestThread::run () i = 2 void MyObject::testSlot () tid = 0x1d98 void TestThread::run () – end
Qt::QueuedConnection(排队方式,是异步) 无论信号从哪个线程发出,信号被发送至接收对象所在线程的信号队列中,需等到接收对象所属线程的事件循环取得控制权(处理完所有事件处于空闲)时才取出该信号并调用对应的槽函数。发送信号的线程中emit语句后的代码将在发出信号后马上被运行,无需等待槽函数运行完成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 void queued_connection () { static TestThread t; static MyObject m; QObject::connect (&t, SIGNAL (testSignal ()), &m, SLOT (testSlot ()), Qt::QueuedConnection); t.start (); t.wait (5 * 1000 ); t.quit (); } int main (int argc, char *argv[]) { QCoreApplication a (argc, argv) ; qDebug () << "main() tid = " << QThread::currentThreadId (); queued_connection (); return a.exec (); }
1 2 3 4 5 6 7 8 9 10 main () tid = 0x1fbc void TestThread::run () – begin tid = 0x32f0 void TestThread::run () i = 0 void TestThread::run () i = 1 void TestThread::run () i = 2 void TestThread::run () – end void MyObject::testSlot () tid = 0x1fbc
注意Qt::QueuedConnection与Qt::DirectConnection
在同线程中使用时,如果信号触发的槽函数中包括exec()函数,需注意:exec()函数相当于打开事件循环,会阻塞掉该槽函数所在的connect()函数,即无法接收到信号。
Qt::QueuedConnection的异步体现在发送信号线程中发送完毕会马上执行接下来的代码,而信号发送到接收者所在线程中也是要信号排队等候执行的(同步)。
exec()不会阻塞和自己同级的connect(),但会阻塞自己所在的connect()。
Qt::BlockingQueuedConnection (信号和槽必须在不同的线程中。否则就产生死锁) 阻塞连接:当前线程发出信号后,当前线程emit后的程序会阻塞,等待其他线程的槽函数执行完毕后才继续执行,相当于是不同的线程能够同步起来运行。
Qt::UniqueConnection 防止重复连接。如果当前信号和槽已经连接过了,就不再连接了。同步异步机制与默认方式一样。