QApplication :: processEvents在不同的线程上

时间:2018-07-02 01:12:32

标签: c++ qt qt5

我有几个问题。

  1. 是否可以在一个线程上初始化QApplication对象,然后在另一个线程上销毁它?

  2. 为什么QApplication必须在分配它的同一线程上运行?

  3. 是否可以在与创建QApplication对象的线程不同的线程上运行QApplication::processEvents()?如果调用processEvents的线程是非QT线程,则可以正常工作吗?

1 个答案:

答案 0 :(得分:2)

  1. 有可能,但尚未测试Qt。我认为有可能侵入其中-您需要更改代码。除非您只考虑QCoreApplication,否则它将永远无法在MacOS上使用– 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::run确实可以做到这一点:它的run()可以做到,实质上是QEventLoop().exec()

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

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

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

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