如何正确停止运行非循环QThread?

How to stop running non-loop QThread correctly?

简介

假设我有一个带有 GUI 的应用程序,它从用户那里收集一些数据,然后调用一个嵌入式 python 脚本。我想添加 "cancel button" 以防用户想要停止进程。

示例代码

mainwindow

#include "calc_script.h"

signals:
    void stopWorkSignal();

private:
    calc_script *sender;

private slots:
    Calculating()
    on_pushButton_Cancel_clicked()



void MainWindow::Calculating()
{
QThread* newThread = new QThread();
connect(newThread, &QThread::started,
        [=]() { sender->transfer(val_1, val_2, val_3); });
connect(this,
    SIGNAL(stopWorkSignal()),
    newThread,
    SLOT(deleteLater())
newThread->start();
}

void MainWindow::on_pushButton_Cancel_clicked()
{
    emit stopWorkSignal();
    qDebug() << "stopwork signal emmitted";
}

calc_script.cpp

void calc_script::transfer(double val_1, double val_2, double val_3)
{
///Here the python (from boost.python) is executed
    while(1) {}//this loop will generate a load to mimic this script, you cannot edit it, as the communication with .py is one-side at this lvl
}

问题 当信号被调用时,我收到错误 QThread destroyed while thread is still running(并且计算似乎仍在进行)。如果我通过 SLOT(quit()),什么也不会发生。如果计算是简单的循环,我可以传递一个标志来中断循环。但是由于调用 python 脚本我无法做到这一点,所以我试图破坏保存计算的线程。执行所述功能的正确方法是什么?

PS。我知道我没有包含对 python 的整个调用,但它很长。对于重现错误,你可以在 transfer 函数中使用任何非循环长计算,它会做基本相同的情况。

你不能强行终止一个线程;您所能做的就是让它退出,然后等待它自行退出。 (确实存在 QThread::terminate() 方法,但您不应该在生产代码中使用它,因为它会导致问题:例如,如果线程在终止时锁定了一个互斥量,则该互斥量将保留永远锁定,您的程序将在下次尝试锁定该互斥锁时死锁并冻结。

所以你有两个选择:要么想办法让 Python 线程退出,要么使用 QProcess object (or something equivalent to it) to run the Python code in a child process instead of inside a thread. The benefit of running the Python code in a separate process is that you can safely kill() 子进程——因为子进程不共享任何声明您的 GUI 进程,OS 将自动清理子进程分配的任何资源,子进程保持互斥锁锁定或其他资源未释放没有问题。

如果您更愿意礼貌地请求 Python 线程(或进程)退出,而不是简单地敲打它,您可以通过网络接口这样做;例如,您可以在 GUI 代码和 Python 事件循环之间创建一个 TCP 连接,并且 Python 事件循环可以在其 TCP 连接的末端定期进行非阻塞读取。然后,当您的 GUI 希望 Python 循环退出时,GUI 可以关闭其 TCP 套接字,这将导致 Python 循环调用 read() 到 return 0(又名EOF),Python 循环知道它的意思是 "time to exit",因此它可以自动退出。