PDA

View Full Version : QThread event handling and QWaitCondition



mattc
21st August 2009, 10:41
Hello,
I have a main thread (GUI) and a worker thread. From the main thread I'm calling a function in the worker thread that waits for a event to be posted on the worker thread's own queue. But it looks like the event is processed only after the main thread gets control back.

Here is a complete test class (test.h) that reproduces the problem. As soon as it is created, the worker thread starts a 5 seconds timer. When you click the button in the main widget, it waits for the timer event to be triggered.


#include <QThread>
#include <QTimer>
#include <QWaitCondition>
#include <QMutex>
#include <QPushButton>
#include <QVBoxLayout>
#include <QMessageBox>

//
// Worker
//
class Worker: public QThread
{
Q_OBJECT
public:
Worker(): tmrNotifyWhenDone(this)
{
// start 5 seconds timer
tmrNotifyWhenDone.setInterval(5000);
connect(&tmrNotifyWhenDone, SIGNAL(timeout()), this, SLOT(onWorkCompleted()));
tmrNotifyWhenDone.start();

// enter thread event loop
start();
}

bool waitForWorkCompleted() // called from the main thread, see below
{
mutex.lock();
bool ok = workCompleted.wait(&mutex, 6000);
mutex.unlock();

return ok;
}

private slots:
void onWorkCompleted()
// this is called only when the message box is shown... WHY?
{
workCompleted.wakeAll();
}

private:
QTimer tmrNotifyWhenDone;
QMutex mutex;
QWaitCondition workCompleted;
};


//
// MainWidget
//
class MainWidget : public QWidget
{
Q_OBJECT
public:
MainWidget(QWidget* parent = 0): QWidget(parent)
{
QPushButton* btnWaitWorkCompleted = new QPushButton("Wait for work completed");
connect(btnWaitWorkCompleted, SIGNAL(clicked()), this, SLOT(onBtnWaitWorkCompleted()));

QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(btnWaitWorkCompleted);
setLayout(layout);
}

private slots:
void onBtnWaitWorkCompleted()
{
if (worker.waitForWorkCompleted())
QMessageBox::information(0, "Test", "Ok!");
else
QMessageBox::information(0, "Test", "Wrong!");
}

private:
Worker worker;
};

numbat
21st August 2009, 12:17
You're having the same problem as this post (http://www.qtcentre.org/forum/f-newbie-4/t-problem-with-threads-23411.html). Only the run function runs in the new thread. The worker object belongs to the thread it was created in, that is the GUI thread. Slots are executed in the thread that their object belongs to.

You can do either of two things. The first is to move ownership of the worker object to the newly created thread with a call to moveToThread(this). The other is to create your object in the run method so it belongs to the new thread as shown in the other post.

mattc
21st August 2009, 13:00
You're having the same problem as this post (http://www.qtcentre.org/forum/f-newbie-4/t-problem-with-threads-23411.html).

Sorry, I didn't notice that post.


Only the run function runs in the new thread. The worker object belongs to the thread it was created in, that is the GUI thread. Slots are executed in the thread that their object belongs to.

Ok, now I understand.


You can do either of two things. The first is to move ownership of the worker object to the newly created thread with a call to moveToThread(this). The other is to create your object in the run method so it belongs to the new thread as shown in the other post.

Thank you very much, I am going to experiment with your solutions.