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;
};
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;
};