>> Because I attached a debugger and stopped T1 during >> QCoreApplication::processEvents(). I can see E3 (the one that the thread is >> currently processing) in postEventList at index 0 and E2 at index 1. That's >> it. From there I see the following call chain >> QEventDispatcherGlib::processEvents() followed by emit awake() because >> canWait is false. I haven't traced it further. The signal emission doesn't >> have any consequence in the event loop though. > > Can you check what happens when it calls into > QCoreApplicationPrivate::sendPostedEvents()? That function should loop from > data->postEventList.startOffset to data->postEventList.size() (size at the > time you call into the function, so no new events wil be handed). > Like you said, it should be handled on the first iteration after it's been > queued.
The problem is that my explicit calls to QCoreApplication::processEvents() do not reach QCoreApplicationPrivate::sendPostedEvents(). I found the root cause: 1. Posted events will increase a counter (serial number) in the glib event dispatcher 2. Before a call into QCoreApplication::sendPostedEvents, the dispatcher stores the current counter value (lastSerialNumber). If multiple events are sitting in the event queue, the counter value will reflect the last posted event. 3. Explicit periodic calls to QCoreApplication::processEvents() go into QEventDispatcherGlib::processEvents() which invokes an iteration in the glib event loop. So far so good. 4. The glib event loop now calls postEventSourcePrepare() which compares the stored lastSerialNumber to the current serial number. This function acts as a filter to decide whether the glib event loop should invoke QCoreApplicationPrivate::sendPostedEvents(). Since it finds lastSerialNumber to be equal to the current serial number, it doesn't do anything. Here is a minimal example of what is happening. It doesn't even need multiple threads: #include <QtCore/QAbstractEventDispatcher> #include <QtCore/QCoreApplication> #include <QtCore/QDebug> namespace { QAtomicInt done = 0; } void E1(); void E2(); void E3(); void E1() { qDebug() << "E1"; QMetaObject::invokeMethod(qApp, &E2, Qt::QueuedConnection); QMetaObject::invokeMethod(qApp, &E3, Qt::QueuedConnection); } void E2() { qDebug() << "E2"; while (done == 0) { QCoreApplication::processEvents(); } QCoreApplication::exit(0); } void E3() { // We never reach this qDebug() << "E3"; done = 1; } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); QMetaObject::invokeMethod(qApp, &E1, Qt::QueuedConnection); app.exec(); } As soon as some other thread posts an event E4 to the current event loop, E3 will be executed, followed by E4 as expected. >> It is a public API and it is not marked as deprecated. If the function does >> not behave as documented, then either the documentation is wrong or the >> implementation has a bug or I am using it the wrong way. I don't think the >> latter is the case, but maybe I need a minimal test case to prove that. > > It's not broken, that's why it's not deprecated. But that doesn't mean it's a > good API. It's not advisable to use nested event loops. processEvents() is > just the worst kind of nested event loops. Sure. Unfortunately, our application relies on QScriptEngine and requires that the engine's thread stays somewhat responsive. Now that I understand the problem, I might be able to implement a work-around in our application. But I would consider this behavior to be a bug in qeventdispatcher_glib. It can never be wrong to fix bugs, even in bad APIs ;-) https://bugreports.qt.io/browse/QTBUG-79020 Richard _______________________________________________ Interest mailing list Interest@qt-project.org https://lists.qt-project.org/listinfo/interest