【发布时间】:2018-07-02 01:12:32
【问题描述】:
我有几个问题。
是否可以在一个线程上初始化 QApplication 对象并在另一个线程上销毁它?
为什么 QApplication 必须在分配它的同一线程上运行?
是否可以在创建 QApplication 对象的不同线程上运行
QApplication::processEvents()?如果调用 processEvents 的线程是非 QT 线程,这会起作用吗?
【问题讨论】:
我有几个问题。
是否可以在一个线程上初始化 QApplication 对象并在另一个线程上销毁它?
为什么 QApplication 必须在分配它的同一线程上运行?
是否可以在创建 QApplication 对象的不同线程上运行QApplication::processEvents()?如果调用 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;
}
为什么不呢? 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”线程。它是平台线程资源的句柄。更好的是:它是在需要时自动创建的句柄,因此您始终可以引用当前线程,即使您的代码之前没有明确创建过这样的句柄。
也许您需要告诉我们您想要做什么。您的问题中缺少一些非常基本的内容。
【讨论】:
processEvents 在这种情况下。