exec of dialog not return in multithreading environment
-
@kshegunov said in exec of dialog not return in multithreading environment:
I'm a physicist,
[ Ah! OT, sorry, but where can I post on this forum to ask you about my (layman's) theories on quantum mechanics? ;-) ]
-
@tmp15711 said in exec of dialog not return in multithreading environment:
Then, if my code is wrong, I want to know the key error, a formally logical analysis
Okay, I'll bite. Since @SGaist duly noted that
QDialog::exec
spins the event loop of the GUI thread, which it most certainly does, if you use only:QMetaObject::invokeMethod(this, "showDialog", Qt::BlockingQueuedConnection);
That means that while you're waiting for input in the dialog in the background signals and slots are still fired. This implies also that your second thread calling the above function will cause the GUI to open a second dialog. Now to prevent this I've added a serialization primitive (the mutex) which ensures that only one of the worker threads can post the
showDialog
call to the UI event loop. When one of the workers finally continues, only then another worker can request a dialog to be shown.where can I post on this forum to ask you about my (layman's) theories on quantum mechanics?
That'd be The Lounge, but don't hold your breath, no one really understands it (it's a math theory anyway).
-
@J.Hilk Then what if QtConcurrent encounters a problem or meets an error? Shouldn't QtConcurrent ask for help and wait for a moment? If I can use Qt::BlockingQueuedConnection, why use slots? I don't need an event loop and slots are really cumbersome in this case.
-
@kshegunov You are correct. I have tested. The mutex approach certaintly works. But why not mine, the event loop approach? I mean why exec doesn't return after the dialog is closed.
@kshegunov Error doesn't mean the threads have to exit. Or, maybe just a warning.
-
@tmp15711 said in exec of dialog not return in multithreading environment:
But why not mine, the event loop approach? I mean why exec doesn't return after the dialog is closed.
Because both of the slots are executed and you have interleaved execution, due to the fact that
exec()
will spin the even loop. Think of it like this:- Thread 1 calls
QDialog::exec
this causes the even loop to continue receiving events - Thread 2 calls
QMetaObject::invokeMethod(this, "showDialog", Qt::BlockingQueuedConnection);
which posts an event to the event loop. Due to 1) that slot starts to execute and a second dialog and a nestedQDialog::exec
is called.
That's why the mutex works, it ensures that only one
QDialog::exec
is called at any one point by serializing the calls toQMetaObject::invokeMethod
.Error doesn't mean the threads have to exit. Or, maybe just a warning.
Then consider using class deriving from
QRunnable
andQObject
to represent your job, and to so you can have signals in it to tell the GUI some error/warning has occurred. Alternatively, I'd suggest following @J-Hilk's advice and just switching to plain oldQThread
classes with worker objects. - Thread 1 calls
-
@kshegunov Thanks. I can reproduce the same behavior with a single thread.
#include <QtCore> struct Object: QObject{ Q_OBJECT public slots: void foo(){ qDebug() << __LINE__; while(entered) qApp->processEvents(); qDebug() << __LINE__; QEventLoop loop; QTimer::singleShot(1000, &loop, SLOT(quit())); entered = true; loop.exec(); entered = false; qDebug() << __LINE__; } private: bool entered = false; }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); Object w; QTimer::singleShot(0, &w, SLOT(foo())); QTimer::singleShot(0, &w, SLOT(foo())); QTimer::singleShot(3000, &a, SLOT(quit())); a.exec(); qDebug() << __LINE__; } #include "main.moc"
In fact, it has nothing to do with multi-threads. I have never studied Qt source code. It seems exec will not return before all slots finish. So, the code actually creates a dead lock.