連接類型
AutoConnection (Qt::AutoConnection):根據對象所在的線程自動選擇合適的連接類型。如果信號發送者和接收者在同一線程中運行,則使用直接連接;否則使用隊列連接。
DirectConnection (Qt::DirectConnection):信號發送時,槽函數會在發送信號的線程中立即執行。適用于信號發送者和接收者在同一線程中運行的情況。
直接連接時,信號與槽之間的響應形式為同步的直接調用,調用流程如下:
emit signal-->QMetaObject::activate-->QSlotObjectBase::call-->receiver::slot
QueuedConnection (Qt::QueuedConnection):信號發送時,將槽函數調用封裝為一個事件并放入接收者所在線程的事件隊列中,槽函數會在接收者的線程中執行。適用于跨線程通信的情況。
隊列連接時,信號發送時,判斷類型為c->connectionType == Qt::QueuedConnection,構造一個MetaCall事件,通過 QCoreApplication::postEvent將事件加到事件隊列中在事件循環處理,調用流程如下:
emit signal-->QMetaObject::activate-->queued_activate ...事件循環...
QEventDispatcherWin32::sendPostedEvents-->QEvent::MetaCall-->receiver::slot
QMetaCallEvent *ev = c->isSlotObject ?
new QMetaCallEvent(c->slotObj, sender, signal, nargs, types, args) :
new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal, nargs, types, args);
QCoreApplication::postEvent(c->receiver, ev);
BlockingQueuedConnection (Qt::BlockingQueuedConnection):(慎用,sender和reciver處于同線程時會出現死鎖)類似于隊列連接,但發送信號的線程會阻塞,直到槽函數在接收者的線程中執行完成。常用于需要確保信號和槽按順序執行的情況。
Qt: Dead lock detected while activating a BlockingQueuedConnection: Sender is Sender(0x32ffe64), receiver is Worker(0x32ffe3c)
UniqueConnection (Qt::UniqueConnection):防止重復連接相同的信號和槽,使用UniqueConnection進行連接時,如果是已存在的連接則本次不會重復連接。
除了加UniqueConnection,否則同一reciver多次connect時都會被加入到列表中,在sender發送信號時被多次調用
QObject::connect(&mainWindow.sender, &Sender::signalToSend, &worker, &Worker::doWork);
QObject::connect(&mainWindow.sender, &Sender::signalToSend, &worker, &Worker::doWork);
recever被銷毀時,自動從sender的list = &connectionLists->at(signal_index);中移除。在QObject對象銷毀時,會把處于posted事件隊列中的事件全部刪除,所以QEvent::MetaCall在對象銷毀后也不會調用。
QObjectPrivate::~QObjectPrivate()
{
...
if (postedEvents)
QCoreApplication::removePostedEvents(q_ptr, 0);
...
}
那么,什么情況下會出現對象銷毀,又觸發信號
void QObjectPrivate::deleteChildren()
為啥對象在delete后,繼續發送關聯該對象槽函數的信號時,觸發的receiver是空的