【问题标题】:Ensuring QProcess termination on termination of its parent QThread确保 QProcess 在其父 QThread 终止时终止
【发布时间】:2012-07-10 11:53:56
【问题描述】:

我正在 Qt 中编写代码,其中我使用多个线程 (Qthreads) 以以下代码 sn-p 所示的方式启动命令行进程:

void test_streamer_thread::run()
{
    QProcess    start_process;
    ...

    ret_status = start_process.execute("some_cmd.exe",some_args);
    start_process.close();
}

一旦启动,进程就会无限运行(在 Windows 任务管理器中显示为单独的进程)。但是,当应用程序终止时,该进程仍然继续存在。如何确保该进程在启动它的应用程序终止时终止。

【问题讨论】:

    标签: multithreading qt


    【解决方案1】:

    完全没有必要使用单独的线程来启动进程。

    确保在应用程序终止时终止子进程的最简单方法是

    QProcess * p = new QProcess(....);
    connect(qApp, SIGNAL(aboutToQuit()), process, SLOT(terminate()));
    

    完整示例见下文。

    这种误解像疾病一样蔓延开来,认为线程是解决每个人问题的方法。我的观察是,在带有Qt标签的10个帖子中有9个,使用线程是不必要的,是不了解问题的结果。

    我的规则是:如果你认为你需要使用线程,试着解释它,如果只是在你的脑海里,以说服你的同事。完成此操作后,请检查您引用来支持您的论点的所有事实是否真实。在许多情况下,它们不是。

    下面的示例代码不会捕获 Unix 信号,因此——正如您在 Linux 和 OS X 上会注意到的——它只会终止直接后代进程,而不是可能从它启动的任何后续进程。你会 need to handle Unix signals 来解决这个问题。

    //main.cpp
    #include <QApplication>
    #include <QPushButton>
    #include <QProcess>
    
    class Launcher : public QObject
    {
        Q_OBJECT
        int n;
        QProcess * process;
    signals:
        void setDisabled(bool);
    public slots:
        void launch() {
            QStringList args;
            args << QString::number(n);
            process = new QProcess(this);
            process->start(QCoreApplication::applicationFilePath(), args);
            connect(qApp, SIGNAL(aboutToQuit()), process, SLOT(terminate()));
            emit setDisabled(true);
        }
    public:
        Launcher(int no) : n(no), process(0) {}
        ~Launcher() {
            if (process) {
                process->terminate();
                process->waitForFinished();
            }
        }
    };
    
    int main(int argc, char ** argv)
    {
        QApplication a(argc, argv);
        int n = 0;
        if (argc > 1) n = QByteArray(argv[1]).toInt();
        Launcher launcher(n+1);
        QPushButton spawn(QString("Spawn #%1").arg(n));
        launcher.connect(&spawn, SIGNAL(clicked()), SLOT(launch()));
        spawn.connect(&launcher, SIGNAL(setDisabled(bool)), SLOT(setDisabled(bool)));
        spawn.show();
        return a.exec();
    }
    
    #include "main.moc"
    

    【讨论】:

      【解决方案2】:

      看起来您正在分叉一个单独的进程,而不是创建线程。

      如果它是一个单独的进程,那么您将需要在父进程和子进程之间进行某种通信(可能是管道或信号)来传达它应该退出的信息。

      如果是线程,在终止进程后,所有线程都会随之死亡。此外,您不会在 Windows 任务管理器中将线程视为单独的进程(不确定它们会如何显示,但它们不会显示为线程)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-10-05
        • 2010-12-26
        • 1970-01-01
        • 2020-09-23
        • 1970-01-01
        • 1970-01-01
        • 2013-11-10
        • 2015-09-08
        相关资源
        最近更新 更多