Qt/C++ 将 worker 的父级更改为 qthread 失败

Posted

技术标签:

【中文标题】Qt/C++ 将 worker 的父级更改为 qthread 失败【英文标题】:Qt/C++ Change parent of worker to qthread fails 【发布时间】:2013-10-10 15:30:52 【问题描述】:

为了减轻我的清理工作,我想将我的工作对象的父对象设置为它被移动到的 Qthread。 (见下文)。

void TelnetServer::incomingConnection(qintptr socketDescriptor)

    QThread * TelnetConnectionThread = new QThread(this);
    TelnetConnection *worker = new TelnetConnection(socketDescriptor,TelnetConnectionThread);
    connect(TelnetConnectionThread, SIGNAL(started()), worker, SLOT(start()));
    connect(TelnetConnectionThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
    worker->moveToThread(TelnetConnectionThread);  // Move worker into QThread
    TelnetConnectionThread->start();  

在 start() 行之前,我添加了:

worker->setParent(TelnetConnectionThread);

但在运行时我看到一个错误,我不能这样做,因为新的父级在不同的线程中。怎么可能?在上面的行中,我将工作线程移到了新线程……所以工作线程应该与 TelnetConnectionThread 在同一个线程中。帮忙?


我通过一些 qDebug's 和 thread() 确认工作线程确实被转移到了新线程!

【问题讨论】:

你应该在连接插槽之前移动到线程,它确保连接是正确的类型 @ratchetfreak 怎么样?连接类型在信号发出时确定。 @thuga 我的错我的印象是 AutoConnection 在连接时被转换为直接或队列 @ratchetfreak 是的,我也这么认为了很长时间。我不确定我从哪里得到这些信息,但我确定我在某个地方读到过它。但后来我注意到在 Qt 文档中它说:The type of connection is determined when the signal is emitted.. 【参考方案1】:

我认为您对 QThread 有点困惑。第一个问题是它的名字相当具有误导性,因为它实际上不是一个线程,而是一个线程控制器。接下来是线程亲和性问题(对象实际运行的线程)。

如果我们从主线程开始并创建一个新的QThread,线程控制器在ma​​in线程中被实例化:-

QThread* pThread = new QThread;

接下来启动线程:-

pThread->start();

即使 pThread 被认为在不同的线程中运行,它的线程亲和性仍然是 ma​​in 线程,但是任何移动到 pThread 的基于 QObject 的类实例都将具有以下线程亲和性新线程:-

QObject* pObject = new QObject;
pObject->moveToThread(pThread);

不过,pThread 的线程亲和性是 ma​​in 线程,而 pObject 的线程亲和性是新线程;请记住,pThread 实际上是一个线程控制器!

将 pObject 的父级设置为 pThread 是错误的,因为它们具有不同的线程亲和性。这是很多人在尝试从 QThread 继承时遇到的问题,而不是将其用作单独的实体并将 QObjects 移至其中。通常发生的情况是,对象有时是在其继承的 QThread 类的构造函数中创建的,而没有为它们提供父级,也没有意识到这些对象将具有主线程的线程亲和性,而不是他们期望的新线程。

将 QObject 移动到另一个线程也会移动其子级,因此尝试将父级设置为线程(线程控制器!)是没有意义的。

总而言之,您不能将工作对象的父对象设置为 TelnetConnectionThread,因为它们在不同的线程上运行。

但是,如果您尝试在完成后自行清理线程,您可以这样做:-

connect(TelnetConnectionThread, SIGNAL(finished()), TelnetConnectionThread, SLOT(deleteLater()));

【讨论】:

啊!我想我明白了。现在,我希望在我的 pThread 被删除时自动删除 QObject。这可能吗(我猜不是通过 setparent)......还是我必须设置另一个与工作人员删除器相关的信号? 在您的示例代码中,您已经将线程的完成信号连接到工作人员的 deleteLater 插槽,它将按照您的要求进行操作。 对不起 - 我的意思是 QThread 对象,所以我必须设置另一个信号。 查看答案底部的连接语句,这不是您要的吗?

以上是关于Qt/C++ 将 worker 的父级更改为 qthread 失败的主要内容,如果未能解决你的问题,请参考以下文章

QT如何摆脱小部件与其父母之间的空间

Qt 设计师;难以将小部件放置在正确的父级中

升级到 Qt 5.15 后,ListView 委托中的父级为空

GroupBox 中 MouseArea 的父级

透明小部件不随其父级移动

PyQt4 & flask:无法为不同线程中的父级创建子级