在Qt程序结束时应该如何退出正在运行的任务子线程?

因个人经验和能力有限,本文仅供参考,有错误或者考虑不完善的地方请各位批评指正。

一、正常情况下如何创建和退出线程

1.继承QThread,重写run()函数

点击折叠或展开代码
// 类的定义
class WorkThread1 : public QThread
{
public:
explicit WorkThread1(QObject *parent = 0);
signals:
// 线程运行完成
void workDone();
public slots:
// 停止线程
void stopThread();
protected:
// 重写run()函数
virtual void run() override;
private:
// 是否停止运行
bool isStop = false;
}; WorkThread1::WorkThread1(QObject *parent) : QThread(parent)
{ }
void WorkThread1::run()
{
for (int i = 0; i < 10; ++i) {
if (isStop) {
return ;
}
// 执行耗时操作
// TODO
}
}
void WorkThread1::stopThread()
{
isStop = true;
} // 外部调用
// 两个按钮,分别开启和停止线程
QPushButton *start = new QPushButton(this);
QPushButton *stop = new QPushButton(this);
WorkThread1 *thread1 = new WorkThread1(this);
connect(start, &QPushButton::clicked, [=](){
thread1->start();
});
connect(stop, &QPushButton::clicked, [=](){
thread1->stopThread();
thread1->wait();
});

2.Qt官方推荐做法,使用moveToThread函数

点击折叠或展开代码
// 任务类
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QString &parameter) {
QString result;
// 耗时操作
// TODO
emit resultReady(result);
} signals:
void resultReady(const QString &result);
}; // 外部调用
class Controller : public QObject
{
Q_OBJECT
// 使用智能指针列表
QList<QPointer<QThread>> workerThreadList;
public:
Controller() {
Worker *worker = new Worker;
QPointer<QThread> workerThread = new QThread;
// 加入管理列表
workerThreadList.append(workerThread);
// 将任务类移入线程
worker->moveToThread(workerThread);
// 连接信号
connect(workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
// 启动线程
workerThread->start();
}
~Controller() {
for (QPointer<QThread> thread : qAsConst(workerThreadList)) {
if (! thread.isNull) {
thread.quit();
thread.wait();
}
}
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};

3. 其他方法快速创建线程任务

点击折叠或展开代码
// QThread静态函数create
QThread *thread = QThread::create([=](){
// 耗时操作
// TODO
});
// QtConcurrent模块,使用时需要在pro文件中引入QT += concurrent,使用头文件#include <QtConcurrent>,可在帮助文档中搜索 Concurrent Run
QtConcurrent::run([=](){
// 耗时操作
// TODO
});
// QRunnable 除非有线程池的需求,否则个人不推荐使用。因为使用起来需要继承和重写,而且使用信号和槽比较麻烦
MyRunnable *r = new MyRunnable; // 需要继承自QRunnable,重写run函数
QThreadPool threadpool;
threadpool.setMaxThreadCount(1);
threadpool.start(r);

二、程序退出时如何退出正在运行的线程

  1. 在耗时的循环操作中添加标志位的判断,在退出时将标志位设置成退出标志位,比如上面的WorkThread1 示例中重写的run函数中的处理方式,如果层级太多,该用全局变量就使用全局变量
  2. 翻阅帮助文档发现QThread有以下两个函数,和标志位差不多的用法
点击折叠或展开代码
    // 请求中断线程
void QThread::requestInterruption()
// 是否请求了中断线程
bool QThread::isInterruptionRequested() const // 使用方法
// 当中断线程时,外部调用
thread->requestInterruption();
// 在线程的任务循环中添加判断
void long_task() {
forever {
if ( QThread::currentThread()->isInterruptionRequested() ) {
return;
}
}
}

三、处理异常情况程序退出后却仍然在后台挂起

在接收到终止信号时,需要退出线程并且退出主线程,可能会因为子线程耗时太长导致程序在后台挂起的情况(可能是这个原因),那么就需要先退出子线程,再退出主线程

点击折叠或展开代码
// 管理线程列表
QList<QPointer<QThread>> mThreadList;
// 创建智能指针
QPointer<QThread> thread = new QThread;
MyObject *obj = new MyObject;
// 移入线程
obj->moveToThread(thread);
// 连接信号和槽
connect(thread, &QThread::finished, obj, &MyObject::deleteLater);
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
// 其他可能的线程正常退出的情况,自定义结束信号finished
connect(obj, &MyObject::finished, [=](){
// TODO
if (! thread.isNull) {
thread->quit();
thread->wait();
}
}); // 程序结束时,循环阻塞,线程全退出后主线程退出
while (mThreadList.size() > 0) {
QPointer<QThread> thread = mThreadList.first();
if ( ! thread.isNull()) {
thread->quit();
thread->wait();
}
mThreadList.pop_front();
}
qApp.exit();

Qt中当程序结束时线程的退出的更多相关文章

  1. QT中控制台程序运行问题

    环境: ubuntu14.04 问题与解决方法: QT中的控制他程序,默认运行方式是直接输出到Output窗口中来.我的程序需要从控制台输入,这时候默认的运行方式就不行了.通过设置工程全选项让它在终端 ...

  2. QT中为程序加入超级管理员权限

    QT的一些文件操作,注册表的操作等,有些操作会无效,主要是因为没有对C盘的相关权限. 解决方法: 1. mingw编译器 在pro工程文件中加入 RC_FILE=main.rc rc文件,之前一篇博客 ...

  3. QT中关于窗口全屏显示与退出全屏的实现

    近期在学习QT时遇到了很多问题这也是其中一个,个人通过在各种书籍和网络上的查阅找到了一些关于这方面的答案,希望能给大家一些帮助. 首先,在QT中对于窗口显示常用的有这么几个方法可以调用: Qt全屏显示 ...

  4. 解决Qt中QTableWidget类方法setItem 时导致程序崩溃问题

    在为一个音乐播放器增加功能时莫明奇妙的出现程序崩溃,定位到是由于QTableWidget 的setItem方法导致的,最终在此处找到了解决方式. 大致是说不能在setItem之前连接cellChang ...

  5. 让linux中的程序崩溃时生成core文件

    当我们的linux程序崩溃的时候,常常会有这样的提示:    Segmentation fault (core dumped)    段错误 (核心已转储)    提示说生成了core文件,但是此功能 ...

  6. QT中给程序加上主界面的图标

    首先在源码目录下面新建一个 myapp.rc的文件,在里面填写如下: IDI_ICON1 ICON DISCARDABLE "myappico.ico" (名字看自己的图片,注意图 ...

  7. boost::asio::socket tcp 连接 在程序结束时崩溃。

    刚开始的时候一直不知道怎么回事,不过幸好我有在每个class 的析构时都打印一条信息. 这个时候发现我的一个tcp_connection (就是自定义的一个连接类) 在最后才被析构. 所以感觉这里可能 ...

  8. IDEA 中scala 程序运行时的错误:报错 test is already defined as object test

    解决办法:在 创建main文件夹和scala文件夹的时候,注意src与这两个文件夹不能同时设置为resources,否则就会产生报错,解决办法将src文件夹的resources取消,右键.

  9. os.popen('python hello_out.py')中Python程序执行时默认的当前路径为MS-DOS CMD的默认路径

    >>> import os >>> os.getcwd() 'D:\\pythonCode\\pp4e' >>> os.chdir('Stream ...

  10. 嵌入式Qt中实现串口读取的事件驱动方法

    在嵌入式Linux系统的UI设计中,比较常见的是使用Qt库来实现.而在Qt中进行程序设计时,也经常会用到串口(UART)通信.现在基于Qt5.1以上的版本中,集成有串口模块(如QSerialPort) ...

随机推荐

  1. bitwarden本地搭建(无需购买SSL证书)

    bitwarden本地搭建(无需购买SSL证书) 在安装之前,笔者在这里先声明一下,我安装bitwarden使用的操作环境为ArchLinux,我的想法是,因为这只是一个"密码本" ...

  2. ABC350

    A link 把最后三位取成数字,判断是否小于\(349\),大于\(1\),不等于\(316\). 点击查看代码 #include<bits/stdc++.h> using namesp ...

  3. 单细胞测序最好的教程(九): 细胞类型自动注释|发表在Science的注释算法

    作者按 本章节主要讲解了基于大模型的自动注释方法,包括CellTypist(发表在Science)和MetaTiME(发表在Nature communication),一个通用,一个泛癌专用.本教程首 ...

  4. python项目位置迁移后,虚拟环境无法使用

    一.虚拟环境无法使用问题 修改虚拟环境目录/pyvenv.cfg文件中的路径 建议以下配置全部替换一下 修改虚拟环境目录/scripts/activate.bat文件中** VIRTUAL_ENV参数 ...

  5. android常用布局基础学习

    总结:可水平放置可垂直放置也可穿插使用,默认为水平 <!--我在第一次使用权重的时候忽视了本线性布局中的宽度与高度,如果要使用权重,请将线性布局的最初大小设置为match_parent,否则不会 ...

  6. 1、Springboot2简介

    在学习 SpringBoot 之前,建议先具备 SpringMVC(控制层).Spring(业务层)和 Mybatis(持久层)的相关知识 1.1.概述 1.1.1.Spring的缺点 Spring ...

  7. 【SpringBoot】02 概述

    [目标] - 什么是SpringBoot? 并不是新技术,只是一个Spring的加强 解脱XML配置,增加了新的注解,但是并不是新的内容 - 新型配置文件技术 YAML - 自动装配原理[了解即可,不 ...

  8. 【Vue】Re02 指令:第一部分

    一.v-once指令 用于固定一次性赋值,后续Vue实例的赋值更改将不再对v-once指令的元素有效 <!DOCTYPE html> <html lang="en" ...

  9. 【SqlServer】02 SSMS工具基本使用入门

    之前的安装中除了SqlServer,还有一个SSMS管理工具 数据库的访问依赖于工具 SSMS提供了两种登陆方式: 创建用户: 删除用户: 创建数据库: 删除数据库: 创建表: 设置表的字段,字段名称 ...

  10. PyTorch显存机制分析

    参考: ======================================================= 在pytorch中有几个关于显存的关键词: 在pytorch中显存为缓存和变量分 ...