QApplication::p rocessEvents 在不同的线程上

QApplication::processEvents on a different thread

本文关键字:线程 rocessEvents QApplication      更新时间:2023-10-16

我有几个问题。

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

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

  3. 是否可以在与创建 QApplication 对象的位置不同的线程上运行QApplication::processEvents()?如果要调用进程事件的线程是非 QT 线程,这会起作用吗?

  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::run正是这样做的:它的run()确实如此,本质上是QEventLoop().exec().

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

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

    没有"非Qt"线程这样的东西。根据定义,线程是平台资源。QThread不是"Qt"线程。它是平台线程资源的句柄。更好的是:它是一个句柄,在有需求时会自动创建,因此你始终可以引用当前线程,即使你的代码之前没有显式创建过这样的句柄。

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