Ensuring QProcess termination on termination of its parent QThread

Using separate threads to launch processes is entirely unnecessary.

The simplest way to ensure that child processes are terminated when the application terminates would be

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

See below for a complete example.

There’s this misunderstadning that is spreading like a disease that threads are the solution to everyone’s problems. My observation is that in 9 out of 10 posts with the Qt tag, the use of threads is unnecessary and is a result of not understanding the problem.

My rule is: if you think you need to use threads, try explaining it, if only in your mind, to convince your coworker. After doing this, check that all the facts you cited to back your argument are in fact true. In many cases, they aren’t.

The example code below does not catch Unix signals, so — as you’ll notice on Linux and OS X — it’ll only terminate the direct descendant process, not any subsequent ones that might have been launched from it. You would need to handle Unix signals to fix that.

//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"

Leave a Comment