gpt4 book ai didi

c++ - QCoreApplication 忽略退出信号并挂起

转载 作者:太空狗 更新时间:2023-10-29 23:40:32 31 4
gpt4 key购买 nike

当信号QCoreApplication::quit()在事件循环开始前被同步触发时,信号被忽略,应用程序永远挂起。但是,从 QTimer 触发,应用程序正确退出。启动可在 exec 循环启动之前立即返回的任务的正确方法是什么?

这是重现此行为的最小代码:

挂.h

#ifndef HANG_H
#define HANG_H

#include <QObject>

class hang : public QObject
{
Q_OBJECT
public:
explicit hang(QObject *parent = 0);

signals:
void done();
public slots:
void foo();
};

#endif // HANG_H

挂起.cpp

#include "hang.h"
#include <iostream>

hang::hang(QObject *parent) :
QObject(parent)
{
}

void hang::foo()
{
std::cout << "foo emit done()" << std::endl;
emit done();
}

主要.cpp

#include <QCoreApplication>
#include <QTimer>
#include <hang.h>

int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
hang obj;

QObject::connect(&obj, SIGNAL(done()), &app, SLOT(quit()));

// obj.foo() does emit done(), but app hang on exec
obj.foo();

// If done() signal is triggered from the timer, app quits correctly
//QTimer::singleShot(0, &obj, SLOT(foo()));

return app.exec();
}

最佳答案

QCoreApplication::quit() 在事件循环开始之前是一个空操作,所以你不能直接调用它。 quit() 方法的语义是:退出正在运行的事件循环。显然,如果没有事件循环在运行,则什么也不会发生。

调用 app.exec() 启动主线程的事件循环。在那个调用之前,事件循环不运行 - 你的一些其他代码正在运行 - 无论是在 main() 主体中的 app.exec() 之前。因此,如果您在 app.exec() 之前调用 quit(),则没有要退出的事件循环,并且 quit() 什么也不做。

在您的代码中,一旦 obj.foo() 发出 done() 信号,app.quit() 就会得到调用。 app.quit() 方法实际上是done() 信号方法的 moc 生成实现中调用的。这是因为连接是直接类型的。信号只是一种机器生成的方法,它从其体内调用所有直接连接,并为排队的连接排队 QMetaCallEvent。因此,就我们的目的而言,obj.foo() 行相当于直接调用 app.quit()。由于您在 app.exec() 运行之前执行此操作,因此它不会执行任何操作,因为没有要退出的事件循环。

相反,您应该将只有在事件循环开始运行后才会被拾取的“东西”加入队列,然后让循环退出然后。一种方法是向应用程序对象发布一个事件,使其退出。

正好内部有一个QMetaCallEvent封装了slot调用。每当 QueuedConnection 用于信号槽连接时,此事件的排队就由信号完成。

因此,当您的信号触发时,有一个 QMetaCallEvent 在内部排队在 gui 线程事件循环的事件队列中。 quit() 槽没有被直接调用,只是一个数据结构被发布到事件队列。但该数据结构对 QObject::event() 有意义 - 它会在遇到事件时重新构造调用。

因此,一旦事件循环开始在 app.exec() 中执行,事件就会被拾取,调用 quit() 槽,然后应用程序退出,因为 app.exec() 在运行事件循环时返回,但被告知退出。 QMetaCallEvent 封装了一个函数调用。它类似于 closure .

您需要做的就是将您的连接更改为排队连接。

// QT 5 syntax
connect(&obj, &hang::done, &app, &app::quit, Qt::QueuedConnection);
// QT 4 syntax
connect(obj, SIGNAL(done()), &app, SLOT(quit()), Qt::QueuedConnection);

关于c++ - QCoreApplication 忽略退出信号并挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19141910/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com