【问题标题】:Race condition with QThread/QDialogQThread/QDialog 的竞争条件
【发布时间】:2011-01-27 13:33:36
【问题描述】:

我试图在以下情况下避免竞争条件:

QDialog* dialog = [...];
QThread* thread = [...];

connect(thread, SIGNAL(finished()), dialog, SLOT(accept()));

thread->start();
dialog->exec();

当线程在 QDialog::exec() 设置对话框之前完成时,由信号触发的“accept()”调用将丢失,对话框不会自行关闭...

所以理想情况下,我只想在对话框准备好处理它之后才启动线程,但我该怎么做呢?

【问题讨论】:

    标签: qt qthread qeventloop


    【解决方案1】:

    诀窍是只有在对话框已经显示时才必须启动线程。因此,一旦引发 QDialog 的 showEvent,您就必须启动它。
    首先,您必须捕获 showEvent,您可以通过使用 QObject::installEventFilterQObject::eventFilter 或通过子类化 QDialog 覆盖 QWidget::showEvent 来实现。
    完成此操作后,您希望发出线程开始的信号。您需要一个自定义信号,您可以在 YourClass::eventFilterYourClass::showEvent 中发出该信号,具体取决于您选择捕获显示事件的方式。
    现在只需将该信号连接到QThread::start() 插槽就可以完成(编辑:使用Qt::QueuedConnection)。

    确保不要两次处理QDialog::accepted() 信号!

    【讨论】:

    • 我认为这种方法仍然存在竞争条件,因为 QDialog::exec() 调用 show() 并且之后才构造并执行事件循环...
    • @hmn: 然后使用Qt::QueuedConnection,并且在控件返回事件循环之前不会发出信号。
    • 我需要 100% 确定它是“正确的”事件循环。我可以确定在从 QDialog::exec() 调用的 MyClass::showEvent() 和 QEventLoop::exec() 之间不会运行任何事件循环吗?
    • @hmn: 是的,你可以,但是嗯.. 我现在不确定这种方法是否可行,我不知道对话框的本地事件循环是否会处理我们的自定义信号.. 如果不是,这行不通 :( .. 试试看吧。
    • @hmn: 我想你可以忘记我上一篇文章的疑惑,根据 qt 博客的一些帖子,本地事件循环将调度在本地事件循环开始之前引发的事件(示例其中关于 QObject::deleteLater,但同样适用于由事件循环处理的所有事件)
    【解决方案2】:

    自从我使用 Qt 以来已经有一段时间了。但是为什么要使用 QThread 来处理对话框中的 Accept 单击?如果它是模态对话框,您可以使用 QDialog::r​​esult(),或者您可以将信号从线程转发到 QDialog::accepted()...

    【讨论】:

      猜你喜欢
      • 2022-01-23
      • 2018-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多