我有一个 3 个 QThreads 相互调用(都继承自 QThread。我知道有些人可能会建议使用 moveToThread,但现在只是忽略这个事实)。简化的代码如下所示:
线程 1 类:
void
Thread1::run
{
// some execution
Thread2 t2 = new Thread2();
connect(t2,SIGNAL(finished),this,SLOT(onFinished));
t2->start();
while(!stop) // stop was initialized as false
{
this->msleep(10);
}
}
void Thread1::onFinished(){ stop = true; }
线程 2 类:
void
Thread2::run
{
// some execution
Thread3 t3 = new Thread3();
connect(t3,SIGNAL(finished),this,SLOT(onFinished));
t3->start();
while(!stop) // stop was initialized as false
{
this->msleep(10);
}
}
void Thread2::onFinished(){ stop = true; }
线程 3 类:
void
Thread3::run
{
// some execution
QMutexLocker ml(&mMutex);
}
当我只有两个线程时,它工作得很好(例如,只有线程 2 和线程 3)。在我转向三线程场景后,onDone() 方法似乎不再与 done() 信号正确连接。thread2 中的 onDone() 曾经被调用过。而且我很确定线程3的执行已经完成。
谁能告诉我我哪里做错了?
首先,您应该注意默认连接类型为 Qt::AutoConnection
。这意味着如果信号从与接收对象的线程不同的线程发出,则使用Qt::QueuedConnection
。在这种情况下: 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.
所以你需要一个事件循环。
它适用于 2 个线程,因为您可能在主线程中运行了一个事件循环。在您仅使用 thread2
和 thread3
对象的情况下,thread2
对象实际上将驻留在主线程中,而thread3
对象将驻留在由thread2
对象管理的线程中。因此thread2
对象中的插槽应该可以工作。
但是在 3 个线程的情况下,thread1
对象将驻留在主线程中,thread2
对象将驻留在由thread1
对象管理的线程中,并且由于那里没有正在运行的事件循环,因此thread2
对象中的插槽将永远不会被执行。
您可以在QThread::run()
函数中调用 QThread::exec(),但请注意,插槽将在 QThread
对象所在的线程中执行,而不是在它管理的线程中执行。因此,您不应该在QThread
子类中使用插槽。您应该创建一个QObject
子类并将其移动到线程中。
另一种选择是在将信号连接到插槽时,使用 Qt::DirectConnection
作为连接类型。