我有几个问题。
是否可以在一个线程上初始化 QApplication 对象并在另一个线程上销毁它?
为什么 QApplication 必须在分配它的同一个线程上运行?
是否可以QApplication::processEvents()在与创建 QApplication 对象的线程不同的线程上运行?如果调用 processEvents 的线程是非 QT 线程,这会起作用吗?
这可能是可能的,但 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;
}
Run Code Online (Sandbox Code Playgroud)为什么不?QApplication根本不需要“跑”,所以谁在乎呢?您可以在任何线程上运行事件循环,而主线程中的事件循环根本不需要运行,除非主线程中有一些对象要向其传递事件。主线程中的事件循环很特别,因为这是唯一QWidget支持实例的循环。这是 Mac OS 的限制,因此如果您想编写可移植的代码,您只能QApplication在主线程(即int main()调用堆栈上的内容)上实例化。
是的,需要注意的是,它不会做您可能认为它可能会做的事情。意思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”线程。它是平台线程资源的句柄。更好的是:它是一个在需要时自动创建的句柄,因此您始终可以引用当前线程,即使您的代码之前没有明确创建这样的句柄。
也许您需要告诉我们您正在尝试做什么。您的问题中缺少一些非常基本的东西。