【问题标题】:Clean up before closing the QCoreApplication在关闭 QCoreApplication 之前清理
【发布时间】:2009-06-10 13:36:11
【问题描述】:

我有一个基于控制台的QCoreApplication,它有计时器并进行套接字通信,还使用锁定的互斥锁。

当我手动关闭应用程序时,它会给出错误消息,指出某些互斥锁已锁定并且已超时。当用户关闭控制台应用程序时,有什么方法可以在控制台应用程序中进行清理吗?

【问题讨论】:

    标签: qt exit


    【解决方案1】:

    清理应该由析构函数和子父关系来处理。

    使您的主对象(主对象)成为 QApplication 的子对象,以便在 QApplication 之前将其与所有子对象一起销毁。

    你确定你杀死了你所有的线程吗?如果是带有事件循环的线程,请务必在调用QThread::wait() 之前调用QThread::quit() 退出事件循环

    您也可以使用 void QApplication::qAddPostRoutine ( QtCleanUpFunction ptr ) 做一些特殊的清理工作。

    要调试这些消息,您可以使用QtMsgHandler qInstallMsgHandler ( QtMsgHandler h ) 并编写自己的消息处理程序来捕获这些警告。如果您可以模拟问题,您可以在消息上设置断点并查看消息来自的堆栈。

    void debugMessageHandler( QtMsgType type, const char *msg ){
        if(QString(msg).contains( "The message you can see in the console" )){
            int breakPointOnThisLine(0);    
        }
    
        switch ( type ) {
            case QtDebugMsg:
                fprintf( stderr, "Debug: %s\n", msg );
                break;
            case QtWarningMsg:
                fprintf( stderr, "Warning: %s\n", msg );
                break;
            case QtFatalMsg:
                fprintf( stderr, "Fatal: %s\n", msg );
                abort();
        }
    }
    

    为了清理析构函数和子父关系,您可以捕获控制台关闭信号并将QCoreApplication::exit() 调用到应用程序实例。

    #include <csignal>
    #include <QtCore/QCoreApplication>
    using namespace std;
    
    struct CleanExit{
        CleanExit() {
            signal(SIGINT, &CleanExit::exitQt);
            signal(SIGTERM, &CleanExit::exitQt);
            signal(SIGBREAK, &CleanExit::exitQt) ;
        }
    
        static void exitQt(int sig) {
            QCoreApplication::exit(0);
        }
    };
    
    
    int main(int argc, char *argv[])
    {
        CleanExit cleanExit;
        QCoreApplication a(argc, argv);
        return a.exec();
    }
    

    【讨论】:

    • 快完成了。一旦你调用了 exit(0),你必须在信号处理程序 exitQt() 之外的某个地方执行 Qt 特定的清理代码。所以你必须将你的 Qt 清理代码与 aboutToQuit() 信号联系起来。 aboutToQuit 信号仅在调用 qApp->exit(0) 时发出。
    • c++11 让它变得更简单:signal(SIGTERM, [](int sig){ qApp-&gt;quit(); });
    • 这并不完全有效。我已将清理相关对象设为 QApplication 的子对象。当窗口正常关闭时,会正确调用析构函数。但是在系统关闭/注销时,永远不会调用 QApplication 子析构函数。
    • 不支持从 unix 信号调用 Qt 函数(可能会挂起、损坏数据等)。见doc.qt.io/qt-5/unix-signals.html。此代码可能会使用户无法通过 ctrl-c 退出程序。另见stackoverflow.com/a/37482031/4973666
    【解决方案2】:

    事实证明,通过按“关闭”(标题栏上的红色 x 按钮)关闭命令行应用程序(在 Win7 和 VS2010 上检查)会将STATUS_CONTROL_C_EXIT 信号传递给应用程序。所有线程都使用此代码中止。

    线程“主线程”(0x980) 已退出,代码为 -1073741510 (0xc000013a)。

    线程 'QThread' (0x2388) 已退出代码 -1073741510 (0xc000013a)。

    这意味着没有办法用QCoreApplication::aboutToQuit() 信号拦截它。

    看看winnt.h 或ntstatus.h。那就是分配给 清单常量STATUS_CONTROL_C_EXIT。运行时只是 选择使用代码结束程序以记录用户的取消 操作。

    【讨论】:

    • 使用 SetConsoleCtrlHandler() 拦截这些,并调用 qApp->exit(42)
    【解决方案3】:

    您可以连接到QCoreApplication::aboutToQuit 信号并在那里进行必要的清理。

    【讨论】:

    • 嗨丹尼尔,我试过这个,但是断点没有在连接的 SLOT 中命中。文档说在 QCoreApplication 上退出时会发出 aboutToQuit 信号。控制台应用程序的关闭是否调用quit()?谢谢,苏雷什。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-29
    • 1970-01-01
    • 2022-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多