跨越QThread的QObject::deleteLater

8
我正在寻找一种方案来安排跨线程删除对象的计划。关于deleteLater函数的行为文档并不完全清晰。我可以在不是对象所有者的线程中调用这个函数吗?
例如,对象X由线程A拥有,在线程B中,我想要删除对象X。由于对象可能正在事件处理中(在线程A中),因此在它返回消息循环之前,我不能安全地删除它。然而,如果我从线程B中调用deleteLater,文档似乎表明它会在Thread B回到消息循环时立即删除。
目前,我采取的方法是在线程A中发出一个信号,该信号连接到一个调用deleteLater的槽中。我想知道是否有更简单的方法来做到这一点--如果确实可以从任何线程中调用deleteLater

在Qt中,您可以更改拥有对象的线程。这对您有帮助吗? - sashoalm
这就是对象进入线程的方式。 - edA-qa mort-ora-y
3个回答

11

查看Qt 4代码Qt 5代码deleteLater()只是显式声明为线程安全的QCoreApplication::postEvent()的调用。因此,直接调用它应该没问题。由于事件队列在对象所属线程中处理,因此删除将在A线程中发生。

只有Qt 5的QObject文档明确列出了deleteLater()是线程安全的。如果您想完全依赖Qt 4中记录的行为,请使用postEvent()


7

虽然 deleteLater() 方法本身并不安全,但你可以在 objectthreadA 中使用元调用来调用它:

metaObject()->invokeMethod(object, "deleteLater", Qt::QueuedConnection);

然后,这将是安全的。

我担心文档中只提到了“主事件循环”来描述这里的排队连接(与通常的排队连接方式非常不同)。这只是文档错误吗?实际上它是否像将一个普通信号推送到另一个线程中那样工作? - edA-qa mort-ora-y
@edA-qamort-ora-y,嗯,看起来这是文档错误,我用了这样的代码删除了对象,但是刚刚在研究Qt源代码时,我发现直接调用deleteLater和元调用一样安全,所以在当前实现中,直接调用可以工作,未来版本的行为可能会在两种情况下令人惊讶。 - Lol4t0
我现在已经追踪了源代码,deleteLater只是发布一个事件,跟踪这些发布的事件将始终发送到接收者的线程所有者。 哎呀!为什么文档不能说同样的话,这样我就不必担心了... :( - edA-qa mort-ora-y
@edA-qamort-ora-y,虽然文档没有说明,但我们可以发现例如qt4.9并不发送事件,而是做了一些不安全的事情,所以请小心。 - Lol4t0
我在qtforums上询问了一下,也许那里有专家。现在,我将坚持使用一种保证可行但复杂的方法。 - edA-qa mort-ora-y
根据我的经验和文档所述:http://qt-project.org/doc/qt-5/threads-qobject.html,“排队连接:当接收者线程的事件循环返回时,调用槽。槽在接收者线程中执行”,这是正确的答案。确保线程A“拥有”对象X,您应该足够安全地安排对象删除方式。 - alediaferia

0

deleteLater() 只是表示对象将在当前事件循环(即 ThreadB)中的所有信号/槽被处理后被删除。

因此,如果 ThreadB 中没有其他槽需要 ObjectX,则等同于普通的 delete

无论您是否可以删除对象以及如何在 ThreadA 中处理它都取决于您的应用逻辑。

如果 ObjectX 是线程的主要对象,则向 ThreadA 发送 quit() 信号是正确的方法。


会有很多这样的对象,线程是一个独立的对象。你确认deleteLater只在当前线程中发生(因此对我的使用不安全)。 - edA-qa mort-ora-y
@edA-qamort-ora-y,这取决于您使用的Qt版本。请参见您问题下面的 Lol4t0 的评论。 - Martin Hennings

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接