QT多线程基础

2023-11-14

简介

相关名词

  • 同步Sync VS 异步Async
    • 同步(手动查询):我调用一个功能,该功能没有结束前,我不断手动查询结果。
    • 异步(主动通知):我调用一个功能,不需要知道该功能结果,该功能有结果后通知我。
  • 阻塞Block VS 非阻塞Unblock
    • 阻塞: 调用我(函数),我(函数)没有接收完数据或者没有得到结果之前,我不会返回。
    • 非阻塞:调用我(函数),我(函数)立即返回,通知调用者。
  • 回调
    • 同步回调:阻塞(无需等待回调完成即可完成其执行)。
    • 异步回调:非阻塞(无需等待回调完成即可完成其执行)。
  • 进程 VS 线程 VS 协程
  • 并发concurrency VS 并行parallelism
    • 并发(交替进行):并发包含多线程,多线程是并发的一种实现方式。
    • 并行(同时进行):多核处理器。
  • 事件循环

QT

使用QThread类。
作用:用线程来处理那些耗时的后台操作,从而让主界面能及时响应用户的请求操作。

运行方式

QThread 的执行从 run() 函数的执行开始

  • run() 函数通过调用 exec() 函数来启动事件循环机制,并且在线程内部处理 Qt 的事件。

基础使用方法

  • QObject::moveToThread()
  • 继承 QThread 类:子类化QThread,然后重写run函数: 旧方法,不推荐
    • run() 中未调用 exec() 开启 even loop =》 run() 执行结束时,线程自动退出。
    • 如果在 WorkerThread 的 run() 中使用了 WorkerThread 的成员变量,而且 QThread的其他方法也使用到了它,即我们从不同线程访问该成员变量,这时需要自行检查安全性

void QObject::moveToThread ( QThread * targetThread )

不能认为 monitor 的控制权归属于新线程(在哪里创建就属于哪里)!仅有槽函数在指定线程中调用,包括构造函数都仍然在主线程中调用。

  • 若使用默认的 run() 方法或自行调用 exec() ,则QThread将开启事件循环
    • QThread->start() 开启线程(调用了 QThread 的 run() 默认开启事件循环)。
    void QThread::run()
    {
        (void) exec();
    }
    
  • QThread 提供 exit() 函数和 quit() 槽
    • 赋予了QThread使用需要事件循环的非GUI类的能力(QTimer、QTcpSocket 等)。
    • 也使得该线程可以关联任意一个线程的信号到指定线程的槽函数。如果一个线程没有开启事件循环,那么该线程中的 timeout() 将永远不会发射。

退出线程过程

在删除 QThread 之前,需要等待 finish 信号 (删除正在运行的 QThread 将导致程序奔溃)。
删除 QThread 对象并不会停止其管理的线程的执行。

  1. 对于未开启事件循环的线程
    仅需让 run() 执行结束即可终止线程:通过 bool 变量进行控制,并定义一个 QMutex 进行加锁保护

  2. 对于开启了事件循环的线程:正常的退出线程其实质是退出事件循环
    若线程中开始开启了 EvenLoop,耗时代码执行结束后,线程并不会退出。退出方法:

  • quit()/exit() + wait()
  • terminate()+ wait():不推荐(强制结束线程是危险的操作)
  • finished信号
connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);

wait(): 等待子线程的结束

Qt - 一文理解QThread多线程(万字剖析整理)
You’re doing it wrong…

实例

  1. Worker类(耗时程序逻辑处理)
// worker.h
class Worker : public QObject
{
    Q_OBJECT
public:
    explicit Worker(QObject *parent = nullptr);
    ~Worker();

public slots:
    void doSomething(const QString& cmd);

signals:
    void resultNotify(const QString& des);
};

// worker.cpp
Worker::Worker(QObject *parent)
    : QObject(parent)
{
}

Worker::~Worker()
{
}

void Worker::doSomething(const QString &cmd)  // 耗时程序
{
    qDebug() << "doSomething()" << cmd << "thread:" << QThread::currentThreadId();
    emit resultNotify("doSomething ok!");
}
  1. Controller类: 外部调用通过Controlleroperate发射信号给workerworker进行耗时程序处理。worker处理完成后,发射信号,controllerhandleResults槽函数接收,确认程序是否正常。
// Controller.h
class Controller : public QObject
{
    Q_OBJECT
public:
    Controller(QObject* parent = nullptr);
    ~Controller();

public slots:
    void handleResults(const QString &des);

signals:
    void operate(const QString &cmd);

private:
    QThread thread;
};

// Controller.cpp
Controller::Controller(QObject* parent)
    : QObject(parent)
{
    Worker *worker = new Worker();
    worker->moveToThread(&thread);  // 移入线程
	connect(this, &Controller::operate, worker, &Worker::doSomething);
    connect(&thread, &QThread::finished, worker, &QObject::deleteLater);  
    connect(worker, &Worker::resultNotify, this, &Controller::handleResults);
    thread.start();
}

Controller::~Controller()
{
    thread.quit();
    thread.wait();
}

void Controller::handleResults(const QString &des)
{
    qDebug() << "handleResults()" << des << "thread:" << QThread::currentThreadId();
}
  1. 调用:
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    Controller* controller = new Controller(this);
    emit controller->operate("copy");
}

https://blog.csdn.net/zyhse/article/details/106313994

QT锁QMutex

QMutexLocker

不能够定义 私有成员变量 和 全局变量,只能够定义局部变量来使用。

使用方法:
(1)先定义一个QMutex类的变量
QMutex m_mutex; (可以是私有成员变量,也可以是全局变量)
(2) 在定义一个QMutexLocker类的变量(注意:在需要上锁的地方直接定义即可)

QMutexLocker locker(&mutex);
a = 5; //等等需要进行写的操作

使用注意:
(1)如果需要对一个全局变量区域进行保护,那么QMutex定义的变量就得是全局的!
(2)QMutexLocker上锁,解锁的原理:在该局部变量被创建的时候上锁,当所在函数运行完毕后该QMutexLocker局部变量在栈中销毁掉(解锁)。
注意,如果该局部变量在中间被打断,那么QMutexLocker上的锁就不会被解锁掉,因为该函数没有被完整的是执行完。QMutexLocker所创建的局部变量也没有被正确销毁销毁,可能就和QMutexLocker他自己本身的机制不服也就不会解锁。

https://www.cnblogs.com/xiangtingshen/p/11078381.html

高级接口

标准库中的future、promise,Qt中的QFuture、QFutureWatcher等。

单例模式(线程安全)

饿汉式单例

class Singleton
{
private:
	Singleton();  // private类型的构造函数,外部(其他类对象)不能直接new一个该对象的实例
public:
	static bool GetSingleton();   // 该类唯一的一个public方法
private:
   static Singleton* m_pSingleton = new Singleton();  // 直接初始化一个实例对象
}

懒汉式单例

class Singleton
{
private:
	Singleton();
public:
	static Singleton GetInstance();
private:
   static Singleton* m_pInstance;
}

Singleton GetInstance()
{
	if (instance == NULL)
	{
		m_pInstance = new Singleton();
	}
	return m_pInstance
}

在多线程并发下这样的实现是无法保证实例实例唯一的,多个线程可以同时进入getInstance()方法。

解决方案

  • 加同步锁 =》 效率低
  • 同步代码块 =》 效率低
  • 使用静态内置类
class Singleton
{
private:
	Singleton();
	static class MySingletonHandler{
		private static MySingleton instance = new MySingleton();
	}
public:
	static Singleton GetInstance();
}

Singleton GetInstance()
{
	return MySingletonHandler.instance;
}
  • 双检查锁机制
Singleton getInstance(){    //对获取实例的方法进行同步
	if (instance == null){
		synchronized(Singleton.class){
			if (instance == null)
				instance = new Singleton();
       }
   }
   return instance;
}

https://blog.csdn.net/cselmu9/article/details/51366946

QT获取线程ID(仅调试使用)

QT获取线程号函数currentThreadId()返回Qt::HANDLE 如何得到QString?

(int)currentThreadId()

问题、Warning

  1. 在加锁状态下无法停止线程,需先解锁。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

QT多线程基础 的相关文章

  • QT学习记录(三)通过ui和代码的方式往窗口添加组件

    写在前面 本文是b站教程的https www bilibili com video BV1g4411H78N p 5 vd source a3efe214b8a2ba185e92e79cb6d6321b的笔记 外加自己的一些其他想法 如有侵
  • 线程安全的单例模式

    线程安全的单例模式 单例模式 属于创建类型的一种常用的软件设计模式 通过单例模式创建的类在当前进程中只有一个实例 一份资源只能被申请加载一次 如何实现 饿汉模式 资源在程序初始化的时候就去加载 后边使用的时候直接使用 使用会非常流畅 但是有
  • java多线程:线程池和阻塞队列

    一 线程池定义和使用 jdk 1 5 之后就引入了线程池 1 1 定义 从上面的空间切换看得出来 线程是稀缺资源 它的创建与销毁是一个相对偏重且耗资源的操作 而Java线程依赖于内核线程 创建线程需要进行操作系统状态切换 为避免资源过度消耗
  • 08C++11多线程编程之unique_lock类模板

    08C 11多线程编程之unique lock类模板 前述 如果看懂了该篇文章 你对unique lock可以说随便使用 并且可以只看第5点的总结即可 1 unique lock概念 当不加参数时 和lock guard一样能自动上锁解锁
  • JUC编程

    1 JUC JUC就是java util concurrent工具包的简称 这是一个处理线程的工具包 JDK 1 5开始出现的 1 传统的synchronized public class Synchronized public stati
  • Disruptor 详解

    Disruptor 详解 想了解一个项目 最好的办法就是 把它的源码搞到本地自己捣鼓 在网上看了 N 多人对 Disruptor 速度的吹捧 M 多人对它的机制分析 就连 Disruptor 官方文档中 也 NB 哄哄自诩 At LMAX
  • 多线程面试总结

    总结 每个对象有一个监视器锁monitor 线程进入同步方法时尝试获取monitor的所有权 其他线程进入阻塞状态 该线程释放monitor的所有权后其他线程重新尝试获取monitor的所有权 只能有一个线程对同步监视器加锁 1 多线程的问
  • Java 线程关闭

    Java线程关闭的方式 1 使用状态位 public class CloseThread extends Thread boolean flag true int index 0 Override public void run while
  • 多线程太可怕了

    今天发现了一个多线程引起的bug 然后进一步体会到 这东西太容易出问题了 首先要说明的是 出问题的代码可不是一般人写的 是由一个叫EPAM systems的世界知名外包公司的人写的 这些java程序员个个经验丰富 心高气傲 貌似base在乌
  • 线程封闭概念

    线程封闭概念 为什么要有线程封闭这个概念呢 多线程中访问共享可变数据时 涉及到线程间数据同步的问题 并不是所有时候都需要共享数据 所以线程封闭概念就出来了 在Java中线程封闭该怎么做呢 可以通过两个方法来做 ThreadLocal 1 T
  • java中什么是并发,如何解决?

    多个进程或线程同时 或着说在同一段时间内 访问同一资源会产生并发问题 银行两操作员同时操作同一账户就是典型的例子 比如A B操作员同时读取一余额为1000元的账户 A操作员为该账户增加100元 B操作员同时为该账户减去 50元 A先提交 B
  • C++-std::unique_lock介绍和简单使用

    unique lock std unique lock比std lock guard更灵活 这种灵活性主要体现在以下几点 lock guard在构造时或者构造前 std adopt lock 就已经获取互斥锁 并且在作用域内保持获取锁的状态
  • Java 多线程模式 —— Guarded Suspension 模式

    Part1Guarded Suspension 模式的介绍 我们只从字面上看 Guarded Suspension 是受保护暂停的意思 1Guarded Suspension 模式 在实际的并发编程中 Guarded Suspension
  • MFC多线程编程之一——问题提出

    原文地址 http www vckbase com document viewdoc id 1704 一 问题的提出 编写一个耗时的单线程程序 新建一个基于对话框的应用程序SingleThread 在主对话框IDD SINGLETHREAD
  • Java如何设置线程的优先级呢?

    转自 Java如何设置线程的优先级呢 线程 thread 是操作系统能够进行运算调度的最小单位 它被包含在进程之中 是进程中的实际运作单位 一条线程指的是进程中一个单一顺序的控制流 一个进程中可以并发多个线程 每条线程并行执行不同的任务 在
  • 并发编程 (6)一不小心就死锁了,怎么办?

    在上一篇文章中 我们用 Account class 作为互斥锁 来解决银行业务里面的转账问题 虽然这个方案不存在并发问题 但是所有账户的转账操作都是串行的 例如账户 A 转账户 B 账户 C 转账户 D 这两个转账操作现实世界里是可以并行的
  • JAVA实现简易HTTP服务器

    说实话 之前完全没有想过 我还能写出服务器 感觉服务器这么高端的东西 能会用就不错了 还能写 不吐槽了 开始了 这次的作业是搭建一个服务器 要能接收请求 并给浏览器返回正确响应 项目的下载地址 项目目标 实现一个简易的多线程服务器 可以处理
  • 并发编程系列之自定义线程池

    前言 前面我们在讲并发工具类的时候 多次提到线程池 今天我们就来走进线程池的旅地 首先我们先不讲线程池框架Executors 我们今天先来介绍如何自己定义一个线程池 是不是已经迫不及待了 那么就让我们开启今天的旅途吧 什么是线程池 线程池可
  • ScheduledThreadPoolExecutor周期定时任务异常处理踩坑的问题!!

    问题原因 在公司写项目的时候 有一个周期定时任务的需求 就想着阿里巴巴开发手册里不是说不能用Executors去创建线程池 因为存在如下问题 FixedThreadPool和SingleThreadPool 允许的请求队列长度为 Integ
  • 多线程编程与性能优化

    引言 在上一篇的入门篇中 我们对Android线程的基础概念和多线程编程模型有了初步了解 本篇将深入探讨多线程编程技术和性能优化策略 以提升应用的效率和响应性 高级多线程编程技术 使用线程池管理线程 线程池是一组预先创建的线程 用于执行任务

随机推荐

  • chrome插件 自动点击页面元素 自动填入内容

    使用较新的 manifest version 3 event 类 项目文件夹 manifest 是配置文件 Bw 是插件图标 background 是一直可以在后台运行的代码 usr input 是点击插件图标时会显示的页面 action1
  • SpringBoot JPA 定义实体类关系:一对一 (增删改查)

    SpringBoot 项目整体结构 pom xml 文件依赖
  • 交换机学习总结

    网络中数据转发主要由交换机和路由器完成 路由器属于网络七层结构的网络层 第三层 交换机一般属于数据链路层 第二层 设备 也有三层交换机和四层交换机 分别属于网络层和传输层设备 路由器负责在不同的局域网内进行数据转发 比如你要访问百度的服务器
  • IOS逆向初探

    前言 这些文章用于记录学习路上的点点滴滴 也希望能给到刚入门的小伙伴们一点帮助 爱而所向 不负所心 环境 iphone 6 MacOS Monterey 12 3 1 一 IOS开发语言 Objective C Objective C是iO
  • 读取npz,并显示图像

    1 import numpy as np import os import matplotlib pyplot as plt import sys import cv2 a np load home wgb Desktop Dex2 tra
  • Python基础11 (End)

    Python基础11 End 学习11 第七章 模块 module 1 模块化 module 程序设计理念 1 Python 程序由模块组成 一个模块对应 python 源文件 一般后缀名是 py 2 模块由语句组成 运行 Python 程
  • 2.反射系列:反射获得泛型参数

    public class Person
  • create user rm identified by rmrm;-- 创建新的用户 --grant 权限1、权限2...to 用户 给创建用户权限 --ex:grant create ses

    create user rm identified by rmrm 创建新的用户 grant 权限1 权限2 to 用户 给创建用户权限 ex grant create session to username 此时只能连接到数据库 gran
  • 山东大学项目实训开发日志——基于vue+springboot的医院耗材管理系统(4)

    经过了几周的努力 前端的页面设计 由我负责的部分 已经基本完成 按照之前的规划 分为首页 订单管理 库存管理 入库管理 出库管理 退货管理 移库管理 报表管理 资质管理 系统管理10个部分 每部分都有专门的页面和操作 在此贴一个移库管理中的
  • 【GPT-4 & ChatGPT】第 2 章 :深入了解GPT-4 和 ChatGPT API

    大家好 我是Sonhhxg 柒 希望你看完之后 能对你有所帮助 不足请指正 共同学习交流 个人主页 Sonhhxg 柒的博客 CSDN博客 欢迎各位 点赞 收藏 留言 系列专栏 机器学习 ML 自然语言处理 NLP 深度学习 DL fore
  • CARLA仿真软件(一)【软件简介及Windows下的安装】

    CARLA基本介绍 CARLA是一个开源的自动驾驶模拟器 它是从头开始构建的 用作模块化和灵活的API 以解决自动驾驶问题中涉及的一系列任务 CARLA的主要目标之一是帮助自动驾驶研发民主化 它是一种易于用户使用和定制的工具 为此 模拟器必
  • 使用阿里云OSS对象存储搭建个人图床

    原文链接 使用阿里云OSS对象存储搭建个人图床 文章目录 一 购买阿里云OSS对象存储 二 创建Bucket 三 获取AccessKey等相关信息 一 购买阿里云OSS对象存储 1 登录阿里云后 搜索OSS 然后点击 立即购买 2 阿里云O
  • IOU、GIOU、DIOU、CIOU、EIOU、Focal EIOU、alpha IOU损失函数分析及Pytorch实现

    IOU Loss 算法作用 Iou的就是交并比 预测框和真实框相交区域面积和合并区域面积的比值 计算公式如下 Iou作为损失函数的时候只要将其对数值输出就好了 def Iou loss preds bbox eps 1e 6 reducti
  • Qt之QProgressBar

    简述 QProgressBar部件提供了一个水平或垂直进度条 进度条用于给用户操作一个进度指示 并向它们说明应用程序仍在运行 简述 详细描述 读取方向 进度方向 效果 源码 文本显示 效果 源码 繁忙指示 效果 源码 QSS 详细描述 可以
  • C++ STL使用

    文章目录 C STL使用 一 什么是STL 二 STL内容介绍 2 1 STL中六大组件 2 2 容器 2 3 迭代器 2 4 算法 2 4 1 算法分类 2 5 仿函数 2 5 1 仿函数 functor 在编程语言中的应用 2 5 2
  • QT5生成.exe文件时,出现缺少QT5core.dll文件解决方法

    在 http qt project org downloads 下载Qt SDK安装需要Qt版本 在QtCreator下 程序可以正常运行 但是当关闭QtCreator后 在DeBug目录下再运行相应的 exe程序时 会提示缺少Qt5Cor
  • 管理工作中的“七种浪费”

    管理工作中的 七种浪费 丰田生产方式中所归纳的 七种 浪费 主要发生在生产现场 但是产生这些浪费的深层次的原因是什么 如果仅仅关注现场存在的问题 而不解决被现象所掩盖的本质问题 无疑是舍本逐末 即使表面上轰轰烈烈 但实际效果也很有限 为了能
  • 刷脸支付在支付前后商家可以做无限延展

    人脸识别的技术传输则需要很强大的流量支撑 才能将人脸复杂的各类生物体特征数据传输到中控电脑里 而5G的超快速度 解决了这一棘手的问题 使得将刷脸支付应用到移动载体上 得到了实现 刷脸支付更大的想象空间在于它的引流能力和交互营销 刷脸支付是一
  • 墙内搭建Android开发环境

    本文首发在我的个人博客 https jlice top p 6s1gi 欢迎大家前去参观 么么哒 提到搭建Android开发环境 一般给出的方案是在Eclipse输入 https dl ssl google com android ecli
  • QT多线程基础

    文章目录 简介 相关名词 QT 运行方式 基础使用方法 void QObject moveToThread QThread targetThread 退出线程过程 wait 等待子线程的结束 实例 QT锁QMutex QMutexLocke