QThread 不会停止/不处理信号

Posted

技术标签:

【中文标题】QThread 不会停止/不处理信号【英文标题】:QThread won't stop / does not process a signal 【发布时间】:2011-09-15 14:50:28 【问题描述】:

我正在尝试在单独的线程中执行一些工作,并在工作完成后停止该线程。

我已经建立了这样的连接

thread.connect( workerClass, SIGNAL( finished() ), SLOT( quit() ) );

但是当我发出 finished() 信号时,quit() 插槽永远不会被调用。命令行不显示任何与失败连接相关的警告。

我创建了一个简单的测试项目来缩小问题范围,我得到了相同的行为:

TestClass.h:

#ifndef TESTCLASS_H
#define TESTCLASS_H
class TestClass : public QObject

    Q_OBJECT
public:
    TestClass()  
signals:
    void finished();
public slots:
    void doWork();

#endif // TESTCLASS_H

TestClass.cpp:

#include "TestClass.h"
#include <QtCore/QDebug>
void TestClass::doWork()

    qDebug() << "Starting";
    for( long i = 0; i < 1000000000; i++ );
    qDebug() << "Done";
    emit finished();
;

和main.cpp:

#include <QtCore/QCoreApplication>
#include <QtCore/QThread>
#include "TestClass.h"

int main( int argc, char* argv[] )

    QCoreApplication a( argc, argv );

    TestClass testClass;
    QThread testThread;

    testClass.moveToThread( &testThread );

    testThread.connect( &testClass, SIGNAL( finished() ), SLOT( quit() ) );
    testClass.connect( &testThread, SIGNAL( started() ), SLOT( doWork() ) );

    testThread.start();
    testThread.wait();

    return 0;

所以这就是我期望发生的事情:

    一旦处理了testThread.start(),就会调用线程的run() 函数,该函数在内部调用exec() 并启动一个事件循环。此外,它还会引发 started() 信号。 testClass 已调用其 doWork() 插槽。 当TestClass::doWork() 完成时,它会抛出一个finished() 信号。 testThread 的事件循环接收信号并将其转发到其quit()testThread.wait() 在线程结束时从等待中返回。

步骤 1-3 有效,我得到了 qDebug() 输出。 问题出在第 4 步:信号被触发并转发到某个事件循环(我对其进行了一点调试,但无法弄清楚它被触发到了哪个事件循环),但从未调用过 quit() 插槽。

我做错了什么?

P.S.:请不要建议子类化 QThread,我尝试这种方式的全部目的是因为我想避免子类化 QThread。

【问题讨论】:

【参考方案1】:

我认为问题在于您实际上没有在场景中运行 Qt 事件循环。如果您将 testThread.wait() 替换为 a.exec()(这会启动 Qt 事件循环),您应该会看到您的信号/插槽得到了正确处理。

如果您希望应用程序在线程完成后退出,您可以使用 QCoreApplication 的 quit() 插槽来执行此操作。

【讨论】:

是的,我认为你是对的。他宁愿做int ret = a.exec(); testThread.wait(); return ret; 线程默认有自己的事件循环,所以我认为这就足够了。事实证明,如果主事件循环没有运行,它们就一文不值。你们是对的。 QThread 只有在调用 int QThread::exec () 时才会运行事件循环。事件循环基本上是在while循环中处理队列的东西。没有处理事件和信号的循环 => 没有信号到达。 从Qt 4.4或其他版本开始,如果你不继承QThread,它默认在run()内调用exec()。这里的问题是缺少主事件循环。【参考方案2】:

我遇到了同样的问题并找到了答案。这是我的问题: What is the use of QThread.wait() function?

要解决您的问题,您不需要运行 a.exec(),您需要做的是,而不是调用尝试向应用程序的事件循环发送信号的 quit()(显然不存在),你必须直接调用它。

所以对于您的代码,请删除以下行:

testThread.connect( &testClass, SIGNAL( finished() ), SLOT( quit() ) );

而不是:

emit finished();

用途:

this->thread()->quit();

Tada...问题解决了。经验教训:不要尝试通过 qt 信号槽机制从其中退出工作线程,因为您的信号不会在它们应该到达的位置结束(您的工作线程的事件循环),但它们最终会在创建改为线程。你永远不知道那个线程在做什么,以及它的事件循环是否正在运行,而且这对你的工作线程不应该有任何影响......相反,直接调用退出。

【讨论】:

以上是关于QThread 不会停止/不处理信号的主要内容,如果未能解决你的问题,请参考以下文章

PyQt5 QThread 不会因终止或标志变量而停止

QThread 的started() 信号没有发出

如何处理 QThread 上的事件?

如何从 GUI 停止 QThread

QThread 中的 Qt 信号和槽

无法关闭 QThread - 应用程序崩溃