我有几个问题。
是否可以在一个线程上初始化QApplication对象,然后在另一个线程上销毁它?
为什么QApplication必须在分配它的同一线程上运行?
是否可以在与创建QApplication对象的线程不同的线程上运行QApplication::processEvents()
?如果调用processEvents的线程是非QT线程,则可以正常工作吗?
答案 0 :(得分:2)
有可能,但尚未测试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;
}
为什么不呢? 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”线程。它是平台线程资源的句柄。更好的是:它是在有需求时自动创建的句柄,因此即使您的代码之前没有明确创建这样的句柄,您也可以始终引用当前线程。
也许您需要告诉我们您要做什么。您的问题中缺少一些非常基本的内容。