首页 > 解决方案 > QApplication::processEvents on a different thread

问题描述

I have a couple questions.

  1. Is it possible to initialize a QApplication object on one thread and destroy it on another?

  2. Why does QApplication have to run on the same thread in which it was allocated?

  3. Is it possible to run QApplication::processEvents() on a different thread from where the QApplication object was created? Will this work if the thread to call processEvents was a non-QT thread?

标签: c++qtqt5

解决方案


  1. 这可能是可能的,但 Qt 没有经过测试。我想有可能破解它 - 你需要更改代码。它永远不会在 MacOS 上运行,除非你只QCoreApplication想到 -QApp..也不QGuiApp..支持该平台上的其他线程,也可能在其他平台上(Windows 除外)。不过,我不知道你为什么要这样做。一旦QApplication事件循环在给定线程上运行,它可以根据命令终止并自动销毁应用程序实例。事实上,这很简单:

    int main(int argc, char *argv[]) {
      QScopedPointer<QCoreApplication> app(new QCoreApplication(argc, argv));
      QtConcurrent::run([]{
        // this runs in a worker thread, and causes the application
        // object to destroy itself and then the program to exit
        QThread::sleep(2);
        QCoreApplication::quit();
      });
      auto rc = app.exec();
      app.reset();
      // perhaps do some other processing here that doesn't need
      // a qApp instance
      return rc;
    }
    
  2. 为什么不?QApplication根本不用“跑”,谁在乎呢?您可以在任何线程上运行事件循环,并且主线程中的事件循环根本不需要运行,除非您在主线程中有一些要向其传递事件的对象。主线程中的事件循环很特别,因为它是唯一QWidget支持实例的循环。这是 Mac OS 的限制,所以如果你想编写可移植的代码,你只能QApplication在主线程上实例化(即int main()调用堆栈上的东西)。

  3. 是的,但需要注意的是,它不会做你可能认为它可能会做的事情。的意思是“清空当前线程QCoreApplication::processEvents的事件队列”。在 Qt 中,事件循环是每个线程的资源。你可以在任何线程上运行一个事件循环——事实上,正是这样做的:它确实如此,本质上。QThread::runrun()QEventLoop().exec()

    而且您只能排空您所在的任何线程的事件循环,因为没有提供对任何其他事件循环的访问权限 - 这没有意义:“排空”事件队列意味着在事件循环的线程中调度事件在该队列上运行,并且当您在任何给定线程中执行时,根据定义,您不会在其他线程中执行代码,因此无法在那里耗尽事件队列。QCoreApplication::processEvents等价于QAbstractEventDispatcher::instance()->processEvents(),其中instance()是当前线程中的事件调度器实例。

    现在您可能会说:但是,如果我们可以获取属于某个其他线程的事件队列数据,并QObject::event在另一个线程中调用所有这些方法呢?这不仅不是为永远工作而设计的,而且您可能只是在内部 Qt 互斥锁上陷入僵局,这就是它的结束。反正也没啥意义。在大多数任何平台上,您都可以向任何线程发送等效的可中断睡眠信号,并注入代码以执行 - 即QCoreApplication::processEvents- 在该信号内。在 Windows 上,你会使用 APC,在 Unix 上,它会是信号和其他聪明代码的某种组合。可以通过堆栈检查来在一定程度上模拟 APC,以确定上下文是否安全,如果是,则执行其他情况下不允许的操作。

    没有“非 Qt”线程之类的东西。根据定义,线程是平台资源。QThread不是“Qt”线程。它是平台线程资源的句柄。更好的是:它是在需要时自动创建的句柄,因此您始终可以引用当前线程,即使您的代码之前没有明确创建过这样的句柄。

也许你需要告诉我们你想要做什么。您的问题中缺少一些非常基本的东西。


推荐阅读