In following code I meet deadlock in someOperation
:
class A : public QObject {
Q_OBJECT
public:
explicit A(QObject* parent) : QObject(parent), data(0) {}
public slots:
void slot1() {
someOperation();
}
void slot2() {
someOperation();
}
void slot3() {
someOperation();
}
private:
void someOperation() {
QMutexLocker lk(&mutex);
data++;
QMessageBox::warning(NULL, "warning", "warning");
data--;
assert(data == 0);
}
int data;
QMutex mutex; //protect data
};
class Worker: public QThread {
Q_OBJECT
public:
explicit Worker(QObject* parent) : QThread(parent) {}
protected:
virtual void run() {
// some complicated data processing
emit signal1();
// other complicated data processing
emit signal2();
// much complicated data processing
emit signal3();
qDebug() << "end run";
}
signals:
void signal1();
void signal2();
void signal3();
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
A* a = new A(&app);
Worker* w = new Worker(a);
QObject::connect(w, SIGNAL(signal1()), a, SLOT(slot1()), Qt::QueuedConnection);
QObject::connect(w, SIGNAL(signal2()), a, SLOT(slot2()), Qt::QueuedConnection);
QObject::connect(w, SIGNAL(signal3()), a, SLOT(slot3()), Qt::QueuedConnection);
w->start();
return app.exec();
}
There is a thread that will emit three signals, all of them queued connected to an instance of class A, and all class A' slots will call to someOperation
, and someOperation
is protected by mutex and it will popup a message box.
Qt::QueuedConnection 2 The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.
It seems slot2 is invoked when slot1's message box still doing modal, in main thread, but at that time slot1 has lock mutex
, so deadlock.
How to change the code to avoid deadlock?
Update:(Jan.17, 2019)
What I want archive is that: slot2 not be execute before slot1 finished.
What should be kept are:
- worker is a background thread to process data, cost long time; so, whatever, the three signals will emit from other thread.
- worker should not blocked by emitting signals.
- slots should execute in main thread, because they will update GUI.
someOperation
is not reentrant.