PDA

View Full Version : postEvent and multithreading



Thymson
22nd December 2008, 12:33
Hi,

Does anyone know what has happened to QApplication:: postEvent and multithreading in Qt 4? If I post an event in another thread than the gui thread, the event is never handled.

Consider this minimal program:


#include <Qt/qapplication.h>
#include <Qt/qthread.h>
#include <iostream>

struct Terminator : QObject {
bool event(QEvent* event) {
std::cerr << "Terminator::event" << std::endl;
return true;
}
};

int main(int argc, char** argv) {
std::cerr << "main thread: " << QThread::currentThreadId() << std::endl;

QApplication app(argc, argv);
QApplication::postEvent(new Terminator,
new QEvent(QEvent::User));
return app.exec();
}

A custom event that terminates the application is posted in the main loop. When QApplication::exec is called, the event is processed. Everything works as expected and the output is:

main thread: 140735005136720
Terminator::event

But if the event is posted in a different thread, it will not be handled. Here's a minimal thread class and accordingly adjusted main function:


struct MyThread : QThread {
void run() {
std::cerr << "MyThread: " << currentThreadId() << std::endl;

QApplication::postEvent(new Terminator,
new QEvent(QEvent::User));
}
};

int main(int argc, char** argv) {
std::cerr << "main thread: " << QThread::currentThreadId() << std::endl;

QApplication app(argc, argv);

MyThread mt;
mt.start();

return app.exec();
}

The output of the program is:

main thread: 139728441435984
MyThread: 1099274576

which means that Terminator::event is never called.

The system is a standard Fedora (2.6.27.5-41.fc9.x86_64) with pthreads. Everything worked in Qt 3, so somewhere along the way something has changed. Any clues?

jpn
22nd December 2008, 13:06
In the latter case Terminator is created in MyThread context. Thus Terminator lives in MyThread and receives events from the event loop of MyThread. But the pitfall is that your MyThread does not run an event loop. The receiving thread must run an event loop. See QThread::exec() for more details.

caduel
22nd December 2008, 13:06
I think the Terminator object is created in the thread's context and the event is somehow transferred to the (not running) event loop of the thread that the event-receiver belongs to (in which case it would never get processed).

from the docs (threads)

A QObject instance is said to live in the thread in which it is created. Events to that object are dispatched by that thread's event loop. The thread in which a QObject lives is available using QObject::thread().

Maybe it works if you create the terminator-object as a global.

HTH

Thymson
22nd December 2008, 13:11
I think the Terminator object is created in the thread's context and the event is somehow transferred to the (not running) event loop of the thread that the event-receiver belongs to (in which case it would never get processed).

from the docs (threads)

Maybe it works if you create the terminator-object as a global.

HTH
You're right! That works. Thanks!

Thymson
22nd December 2008, 13:22
It also worked to change the thread "affinity".


Terminator* t1 = new Terminator;
t1->moveToThread(QApplication::instance()->thread());
QApplication::postEvent(t1, new QEvent(QEvent::User));


And that solves my specific problem. :)