連接類型
AutoConnection (Qt::AutoConnection):根據(jù)對(duì)象所在的線程自動(dòng)選擇合適的連接類型曹宴。如果信號(hào)發(fā)送者和接收者在同一線程中運(yùn)行滞谢,則使用直接連接旱易;否則使用隊(duì)列連接偏瓤。
DirectConnection (Qt::DirectConnection):信號(hào)發(fā)送時(shí)份乒,槽函數(shù)會(huì)在發(fā)送信號(hào)的線程中立即執(zhí)行恕汇。適用于信號(hào)發(fā)送者和接收者在同一線程中運(yùn)行的情況。
直接連接時(shí)或辖,信號(hào)與槽之間的響應(yīng)形式為同步的直接調(diào)用瘾英,調(diào)用流程如下:
emit signal-->QMetaObject::activate-->QSlotObjectBase::call-->receiver::slot
QueuedConnection (Qt::QueuedConnection):信號(hào)發(fā)送時(shí),將槽函數(shù)調(diào)用封裝為一個(gè)事件并放入接收者所在線程的事件隊(duì)列中孝凌,槽函數(shù)會(huì)在接收者的線程中執(zhí)行方咆。適用于跨線程通信的情況。
隊(duì)列連接時(shí)蟀架,信號(hào)發(fā)送時(shí)瓣赂,判斷類型為c->connectionType == Qt::QueuedConnection,構(gòu)造一個(gè)MetaCall事件片拍,通過 QCoreApplication::postEvent將事件加到事件隊(duì)列中在事件循環(huán)處理煌集,調(diào)用流程如下:
emit signal-->QMetaObject::activate-->queued_activate ...事件循環(huán)...
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處于同線程時(shí)會(huì)出現(xiàn)死鎖)類似于隊(duì)列連接捌省,但發(fā)送信號(hào)的線程會(huì)阻塞苫纤,直到槽函數(shù)在接收者的線程中執(zhí)行完成。常用于需要確保信號(hào)和槽按順序執(zhí)行的情況纲缓。
Qt: Dead lock detected while activating a BlockingQueuedConnection: Sender is Sender(0x32ffe64), receiver is Worker(0x32ffe3c)
UniqueConnection (Qt::UniqueConnection):防止重復(fù)連接相同的信號(hào)和槽卷拘,使用UniqueConnection進(jìn)行連接時(shí),如果是已存在的連接則本次不會(huì)重復(fù)連接祝高。
除了加UniqueConnection栗弟,否則同一reciver多次connect時(shí)都會(huì)被加入到列表中,在sender發(fā)送信號(hào)時(shí)被多次調(diào)用
QObject::connect(&mainWindow.sender, &Sender::signalToSend, &worker, &Worker::doWork);
QObject::connect(&mainWindow.sender, &Sender::signalToSend, &worker, &Worker::doWork);
recever被銷毀時(shí)工闺,自動(dòng)從sender的list = &connectionLists->at(signal_index);中移除乍赫。在QObject對(duì)象銷毀時(shí),會(huì)把處于posted事件隊(duì)列中的事件全部刪除陆蟆,所以QEvent::MetaCall在對(duì)象銷毀后也不會(huì)調(diào)用雷厂。
QObjectPrivate::~QObjectPrivate()
{
...
if (postedEvents)
QCoreApplication::removePostedEvents(q_ptr, 0);
...
}
那么,什么情況下會(huì)出現(xiàn)對(duì)象銷毀叠殷,又觸發(fā)信號(hào)
void QObjectPrivate::deleteChildren()
為啥對(duì)象在delete后改鲫,繼續(xù)發(fā)送關(guān)聯(lián)該對(duì)象槽函數(shù)的信號(hào)時(shí),觸發(fā)的receiver是空的