关于 QThread、QObject、线程关联和事件循环的混淆

Posted

技术标签:

【中文标题】关于 QThread、QObject、线程关联和事件循环的混淆【英文标题】:Confusion regarding QThread, QObject, Thread Affinity and Event Loop 【发布时间】:2014-07-18 20:23:37 【问题描述】:

我正在浏览链接

    You are doing it wrong Using QThread in right way Part1 Using QThread in right way Part2

我对一些陈述感到困惑。在第一个链接中,它说

QThread 中的所有函数都是编写并打算从创建线程调用,而不是从 QThread 启动的线程调用。

虽然它建议使用moveToThread 将对象移动到新线程,而不是继承QThread。我的问题是:

run 方法的默认实现调用exec,这会创建一个事件循环,并且当使用moveToThread 更改对象的线程亲和度 时,所有slots 将在新线程中执行,而不是在创建线程中执行,这与上述预期用途相矛盾。我错过了什么吗?

第二个问题:

在第三个链接中说

事件队列属于线程,而不是事件循环,它被运行在该线程中的所有事件循环共享。

我的问题是如何在一个线程中有多个事件循环?我的理解是,event-loop 循环通过 event-queue,直到调用 exit/terminate,并处理每个到达该队列的 event .如果这是真的,一个循环将永远不会结束(除非exit/terminate 被调用),另一个循环如何开始?任何演示它的示例代码都将受到高度赞赏。

【问题讨论】:

您错过了“如何真正、真正地使用 QThreads;完整说明”:mayaposch.wordpress.com/2011/11/01/… @Merlin069,我研究过,但没有提及,与我的问题无关。 对不起,我当时没时间回答。 谁否决了这个问题,请解释原因。 建议将QThread以外的对象移至线程。因此,除了run 之外没有QThread 方法在新线程中执行。 【参考方案1】:

“这与上述预期用途相矛盾。我错过了什么吗?”

是的,我认为您误解了线程亲和性(对象正在运行的线程)的概念。

让我们以最少的代码为例:-

QThread* pThread = new QThread; // QThread on the main thread
MyObject* myObj = new MyObject; // MyObject on the main thread
myObj->moveToThread(pThread);   // MyObject on the new thread, controlled by pThread
pThread->start();               // pThread instance is still on the main thread

假设这段代码是从一个线程亲和性为主线程的对象创建的,例如QMainWindow,则线程对象pThread在主线程上运行;它的线程亲和性是主线程。

相比之下,QObject 派生的MyObject 实例myObj 已移至新线程pThread。所以,myObj 的线程亲和性现在是新线程。

QThread编写的函数”仍然直接从主线程调用,因为它是在主线程运行的。

QThread 视为线程控制器对象,而不是线程本身。这是通常不鼓励从QThread 继承的原因之一,除非您想更改QThread 管理底层线程的方式。

如何在一个线程中有多个事件循环?...

我自己并没有直接使用过这个,但我会尽量按照我的理解来解释。也许其他人将能够纠正或确认这一点。来自Qt Documentation for QEventLoop,它指出:-

您可以随时创建QEventLoop 对象并在其上调用exec() 以启动本地事件循环。

来自 QEventLoop exec 的签名是:-

int QEventLoop::exec (ProcessEventsFlags flags = AllEvents)

因此,如果您传入一组标志,则只会处理这些事件。现在,调用exec() 开始处理事件,直到调用exit(),您可以创建一个本地事件循环,让您的程序等待一个或多个特定事件发生。

第二个事件循环是主事件循环中的一个本地事件循环,但由于每个事件循环都可以处理整个事件队列,该队列由线程中的所有事件循环共享,它可以用来覆盖从主事件循环。

如果您将事件循环概念化为执行以下操作(伪代码):-

QList<QEvent*> eventList;
while(!stop)

    // handle events in eventList

第二个事件循环会这样做:-

bool bStop = false;
QList<QEvent*> eventList;
while(!bStop)

    // handle events in eventList
    ...
    ...
    // Inner event loop
    bool bStop = false;
    while(!bStop)
    
        // handle events in eventList
    

【讨论】:

感谢您的意见。如果我的理解是正确的,那么第一个问题仍然存在,而不是文章自相矛盾。但是您对第二个问题的回答确实很有帮助。 +1 你能解释一下你在哪里看到了矛盾吗? QThread 的预期用途是从创建对象的线程调用它的函数,而移动到该线程的对象的函数在新线程中运行和调用。 你最后的评论实际上澄清了我的困惑。

以上是关于关于 QThread、QObject、线程关联和事件循环的混淆的主要内容,如果未能解决你的问题,请参考以下文章

重点:怎样正确的使用QThread类(注:包括推荐使用QThread线程的新方法QObject::moveToThread)

Qt QThread与QObject的关系

QThread 与 QObject的关系?

驻留在 QThread 内的 QObjects 会自动删除吗?

Qt线程的简单使用

QT多线程操作