连接类型
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是空的