In QT multithreading, the problem that object signals and slots cannot be connected
Reprinted: https://blog.csdn.net/xytx_823/article/details/51819474
There are many kinds of problems that cannot be connected, such as the parameter mismatch between the signal and the slot, the parameter is a custom type, and so on. A problem encountered today is that in multi-threading, signals and slots cannot be connected all the time. To prevent forgetting, record it.
The scenario of this problem is that a derived class of QObject is not created in the main thread, and then the derived class uses the default connection method to connect the signal, which cannot be connected at this time.
The root of the problem is that when connecting asynchronously, the signal is handled by the event processing mechanism of the thread where the receiver is located. If the thread where the receiver is located has no event handling, the signal will not be handled. Take a look at the code:
voidQCoreApplication::postEvent(QObject*receiver,QEvent*event, int priority)
{
if (receiver == 0) {
qWarning("QCoreApplication::postEvent: Unexpected null receiver");
delete event;
return;
}
QThreadData* volatile *pdata= &receiver->d_func()->threadData;
QThreadData*data = *pdata;
if (!data) {
// postingduring destruction? just delete the event to prevent a leak
delete event;
return;
}
// lock the postevent mutex
data->postEventList.mutex.lock();
// if object hasmoved to another thread, follow it
while (data != *pdata) {
data->postEventList.mutex.unlock();
data =*pdata;
if (!data) {
//posting during destruction? just delete the event to prevent a leak
delete event;
return;
}
data->postEventList.mutex.lock();
}
QMutexUnlockerlocker(&data->postEventList.mutex);
// if this is oneof the compressible events, do compression
if (receiver->d_func()->postedEvents
&& self&& self->compressEvent(event,receiver,&data->postEventList)){
return;
}
if (event->type() ==QEvent::DeferredDelete&&data == QThreadData::current()) {
// rememberthe current running eventloop for DeferredDelete
// eventsposted in the receiver's thread
static_cast<QDeferredDeleteEvent *>(event)->level =data->loopLevel;
}
// delete theevent on exceptions to protect against memory leaks till the event is
// properly ownedin the postEventList
QScopedPointer<QEvent>eventDeleter(event);
data->postEventList.addEvent(QPostEvent(receiver,event, priority));
eventDeleter.take();
event->posted =true;
++receiver->d_func()->postedEvents;
data->canWait =false;
locker.unlock();
QAbstractEventDispatcher*dispatcher =data->eventDispatcher.loadAcquire();
if (dispatcher)
dispatcher->wakeUp();
}
As can be seen from the above, the signal is packaged as an event and added to the event queue of the thread where the receiver is located.
Several solutions that come to mind temporarily:
1. In the receiver creation thread, move the receiver to the main thread:
pReceiverObj->moveToThread(QApplication::instance()->thread());
2. Send the signal like this At that time, it will be processed in the main thread event queue processing.
Change the last parameter of connect to Qt::DirectConnection, and use direct connection to connect signals and slots.
3. Start QThread's own event queue processing (exec()).
If there are any mistakes and problems, please advise.
The problem I am currently encountering is solved using the first method