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

问题描述 投票:0回答:1

Introduction

假设我有一个带有GUI的应用程序,该应用程序从用户那里收集一些数据,然后调用嵌入式python脚本。我想添加“取消按钮”,以防用户想要停止该过程。

示例性代码

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脚本,所以无法执行此操作,因此我尝试破坏保存计算的Thread。做所述功能的正确方法是什么?

PS。我知道我没有包括对python的全部调用,但是它很长。对于再现错误,您可以在transfer函数中使用任何非循环长计算,这将在基本上相同的情况下进行。

python c++ qt boost qthread
1个回答
0
投票

您不能强行终止线程;您能做的就是要求它退出,然后等待它退出。 (确实存在QThread::terminate()方法,但是您不应在生产代码中使用它,因为它会引起问题:例如,如果线程在终止时已锁定了互斥锁,则该互斥锁将永远保持锁定状态,并且您的程序在下次尝试锁定该互斥锁时将死锁并冻结。

因此,您有两个选择:找出一种方法来请求Python线程退出,或者使用QProcess对象(或与其等效的对象)在子进程中而不是在线程内部运行Python代码。在单独的进程中运行Python代码的好处是,您可以安全地kill()子进程-因为该子进程不与您的GUI进程共享任何状态,并且操作系统会自动清理由子进程,子进程没有问题,互斥锁处于锁定状态或其他资源未被释放。

[如果您宁愿要求Python线程(或进程)退出而不是简单地敲打它,您可以通过网络接口进行操作;例如,您可以在GUI代码和Python事件循环之间创建TCP连接,而Python事件循环可以在TCP连接结束时定期进行非阻塞读取。然后,当您的GUI希望退出Python循环时,GUI可以关闭其TCP套接字,这将导致Python循环对read()的调用返回0(又称EOF),Python循环将知道这意味着“退出时间” “,这样它便可以自动退出。

© www.soinside.com 2019 - 2024. All rights reserved.