简体   繁体   中英

Kill a QProcess running in a different QThread

I have a class that inherits QThread and I reimplemented the run() method. In this run method, there's a QProcess (declared in run) that starts a program.

Now if I close my application while that process is still running, it actually won't close until the process finishes.

So my question is how do I stop this process ?

From what I've read in Qt docs, I cannot use signal/slot here since my process will have thread affinity with a thread that is not the main thread, so the connections are queued and this doesn't stop my process.

I'm using Qt 5.8

Thanks in advance !

EDIT: here's the thread code, let me know if you need more

void run()
{
    QString cmd;
    QProcess p;

    connect(&p, SIGNAL(finished(int)), this, SLOT(quit()));
    //connect(this, SIGNAL(signalTerminateProcess()), &p, SLOT(kill())); // queued connect that doesn't kill my process

    p.start(cmd);
    if(p.waitForFinished(-1))
    {
        qInfo("process done");
    }
}

First, you can use signal & slots across QThreads and you can even wait for the slot to be executed using Qt::BlockingQueuedConnection . See Qt documentation .

However, this requires the target QObject to live in a thread that has a running event loop. In your case, since you have overloaded QThread::run() , you will not have an event loop.

As I see it, you have 2 ways of fixing your code either you do a small fix or you change the design and use the event loop.

1. Quick fix

void run()
{
    QString cmd;
    QProcess p;

    connect(&p, SIGNAL(finished(int)), this, SLOT(quit()));
    //connect(this, SIGNAL(signalTerminateProcess()), &p, SLOT(kill())); // queued connect that doesn't kill my process

    p.start(cmd);
    while(! p.waitForFinished(100)) //Wake up every 100ms and check if we must exit
    {
        if (QThread::currentThread()->isInterruptionRequested())
        {
            p.terminate();
            if (! p.waitForFinished(1000))
                p.kill()
            break;
        }
    }
    qInfo("process done");
}

int cleanUp()
{
    thread->requestInterruption();
    thread->wait();
}

or

QProcess *process = nullptr;
void run()
{
    QString cmd;
    QProcess p;
    process = &p; //You shouldn't do that in real code

    connect(&p, SIGNAL(finished(int)), this, SLOT(quit()));
    //connect(this, SIGNAL(signalTerminateProcess()), &p, SLOT(kill())); // queued connect that doesn't kill my process

    p.start(cmd);
    while(! p.waitForFinished(100)) //Wake up every 100ms and check if we must exit
    {
        QCoreApplication::processEvents();
    }
    qInfo("process done");
    process = nullptr;
}

int cleanUp()
{
    QTimer::singleShot(0, process, &QProcess::terminate);
    // Qt 5.10 -> QMetaObject::invokeMethod(process, &QProcess::terminate);
    if (! thread->wait(1000))
    {
        QTimer::singleShot(0, process, &QProcess::kill);
        thread->wait();
    }
}

2. Event loop fix

// Create thread
QThread thread;
thread.start();

// Create process and move it to the other thread
QProcess process;
process.moveToThread(&thread);

void startProcess()
{
    p.start(cmd);
}

QMutex mutex;
void stopProcess()
{
    p.terminate();
    if (!p.waitForFinished(1000))
        p.kill();
    p.moveToThread(qApp->thread());
    mutex.unlock();
}

// Call startProcess() in the other thread
QTimer::singleShot(0, &process, &startProcess);

// Call stopProcess() in the other thread
mutex.lock();
QTimer::singleShot(0, &process, &stopProcess);
mutex.lock();

thread.quit();
if (!thread.wait(100))
    thread.terminate();

You can :

  • Replace the mutex by using an atomic or using signals connected with Qt::BlockingQueuedConnection .
  • Replace startProcess() and stopProcess() by slots and lambdas.
  • Replace calls to QTimer::singleShot() by QMetaObject::invokeMethod() or by using signals. Note thate you can use Qt::BlockingQueuedConnection with QMetaObject::invokeMethod()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM