[Qt-interest] Interesting QThread problem
Yifei Li
yifli at mtu.edu
Tue Nov 23 23:18:57 CET 2010
Hi folks,
My app loads user plugins and runs them using individual threads. In a plugin, users can programmatically pause the execution of the thread until the thread is resumed by the app.
However, if I terminate the thread's execution and re-start it, the thread seems to be blocked indefinitely.
The following code is a minimal example of what I'm trying to do. Once the plugin prints out one message, it will wait until 'Next' button is clicked to print out the next message. Try to terminate the execution by clicking 'Stop' and then start the execution. You will notice the first message is printed out fine. But when you click on 'Next' button to print the second message, the whole app seems to deadlock.
#include <QtGui/QApplication>
#include <QThread>
#include <QTextEdit>
#include <QDialog>
#include <QGridLayout>
#include <QPushButton>
#include <QWaitCondition>
#include <QMutex>
class Plugin : public QObject {
Q_OBJECT
public:
void exec() {
emit log("Message 1");
emit pause();
emit log("Message 2");
emit pause();
emit log("Message 3");
emit pause();
emit log("Message 4");
emit pause();
emit log("Message 5");
emit pause();
}
signals:
void log(QString);
void pause();
};
class MyThread : public QThread {
Q_OBJECT
public:
MyThread(Plugin* p, QWaitCondition* wc, QMutex* mutex)
: m_plugin(p), m_wc(wc), m_mutex(mutex) {}
private slots:
void slotPause() { m_wc->wait(m_mutex); }
protected:
void run() { m_plugin->exec(); }
private:
Plugin* m_plugin;
QWaitCondition* m_wc;
QMutex* m_mutex;
};
class MyWidget : public QWidget {
Q_OBJECT
public:
MyWidget(QWidget* parent=0);
~MyWidget() { delete m_plugin; delete m_mutex; delete m_wc; delete m_thread; }
private slots:
void start();
void next();
void stop();
private:
QTextEdit* m_edit;
QPushButton *m_start, *m_next, *m_stop;
Plugin* m_plugin;
MyThread* m_thread;
QWaitCondition* m_wc;
QMutex* m_mutex;
};
#include "main.moc"
MyWidget::MyWidget(QWidget* parent)
:QWidget(parent)
{
m_wc = new QWaitCondition;
m_plugin = new Plugin;
m_mutex = new QMutex;
m_thread = new MyThread(m_plugin, m_wc, m_mutex);
QGridLayout* layout = new QGridLayout(this);
m_edit = new QTextEdit;
m_start = new QPushButton("Start");
m_next = new QPushButton("Next");
m_next->setEnabled(false);
m_stop = new QPushButton("Stop");
m_stop->setEnabled(false);
layout->addWidget(m_edit, 0, 0, 1, 3);
layout->addWidget(m_start, 1, 0);
layout->addWidget(m_next, 1, 1);
layout->addWidget(m_stop, 1, 2);
connect(m_start, SIGNAL(clicked()), this, SLOT(start()));
connect(m_next, SIGNAL(clicked()), this, SLOT(next()));
connect(m_stop, SIGNAL(clicked()), this, SLOT(stop()));
connect(m_plugin, SIGNAL(log(const QString&)), m_edit, SLOT(append(const QString&)));
connect(m_plugin, SIGNAL(pause()), m_thread, SLOT(slotPause()), Qt::DirectConnection);
}
void MyWidget::start()
{
m_start->setEnabled(false);
m_next->setEnabled(true);
m_stop->setEnabled(true);
m_plugin->moveToThread(m_thread);
m_thread->start();
}
void MyWidget::next()
{
m_wc->wakeAll();
}
void MyWidget::stop()
{
m_start->setEnabled(true);
m_next->setEnabled(false);
m_stop->setEnabled(false);
m_thread->terminate();
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyWidget w;
w.show();
return a.exec();
}
More information about the Qt-interest-old
mailing list