Qt信号槽多线程死锁

qt signal-slot multithreading deadlocks

本文关键字:死锁 多线程 信号 Qt      更新时间:2023-10-16

在我的代码中,一个工作线程向gui线程发出一个信号。信号和插槽通过Qt::BlockingQueuedConnection连接。

closeEvent应用程序试图停止工作线程,然后才完成事件时。

调用工作线程的函数:

void stop() {
  _isFinished = true;
  wait();
}

工作线程依次检查_isFinished条件,如果没有设置,则发出信号。

想象下列情况

The worker            Gui Thread 
=================     =================
if (!_isFinished)     -----------------
-----------------     _isFinished = true;
-----------------     wait();
emit mySignal();      -----------------

显然,两个线程都会被锁死锁。

如果我添加一个互斥锁,那么你会发现另一个死锁的情况。当工作线程锁定互斥锁时,gui线程将被阻塞。因此,发出的信号将锁定工作线程。

我该如何处理?

我是这么看的

在主线程中,你不需要等待worker退出。相反,你的closeEvent应该看起来像这样:

if (workerThread->isRunning())
{
    workerThread->stop();
    event->ignore();
}

要使此工作,您还需要关闭主窗口,当工作线程完成:

connect(workerThread, SIGNAL(finished()), SLOT(close()));

最后,所有对_isFinished(以及工作线程中的所有其他变量)的操作都应该发生在工作线程中。您可以使用一个简单的技巧来实现它:

WorkerThread.h

public:
    void stop();
protected slots:
    void p_stop();
protected:
    QMutex mutex;

WorkerThread.cpp

void WorkerThread::stop()
{
    staticMetaObject.invokeMethod(this, "p_stop", Qt::QueuedConnection);
}
void WorkerThread::p_stop();
{
    QMutexLocker locker(&mutex);
    _isFinished = true;
}

在gui线程中,您可以使用QEventLoop进行等待。像这样:

void stop() {
    QEventLoop eventloop;
    connect(&theWorkerThread, &QThread::finished, &eventloop, QEventLoop::quit);
    _isFinished = true;
    eventloop.exe();
}