【Qt】多线程

多线程

  • QThread 类简介
  • 使用线程
  • 线程同步
    • 互斥锁

QThread 类简介

一个 QThread 类的对象管理一个线程。在设计多线程程序的时候,需要从 QThread 继承定义线程类,并重新定义 QThread 的虚函数 run(),在函数 run() 里处理线程的事件循环。

应用程序的线程称为主线程,创建的其他线程称为工作线程。一般会在主线程里创建工作线程,并用函数 start() 开始执行工作线程的任务。函数 start() 会在其内部调用函数 run() 进入工作线程的事件循环,函数 run() 的程序体一般是一个无限循环,可以在函数 run() 里调用函数 exit() 或 quit() 结束线程的事件循环,或在主线程里调用函数 terminate() 强制结束线程。

QThread 常用 API

函数功能
run()线程的入口函数
start()通过调用 run() 开始执行线程。操作系统将根据优先级参数调度线程。如果线程已经在运行,这个函数什么也不做
cuttentThread()返回一个指向管理当前执行线程的QThread的指针
isRunning()如果线程正在运行则返回 true,否则返回 false
sleep() / msleep() / usleep()使线程休眠,单位为秒 / 毫秒 / 微秒
wait()阻塞线程,直到满足以下任何一个条件:
与此 QThread 对象关联的线程已经完成执行(即当它从run() 返回时)。如果线程已经完成,这个函数将返回 true。如果线程尚未启动,它也返回 true。
已经过了几毫秒。如果时间是 ULONG_MAX(默认值),那么等待永远不会超时(现成必须从 run() 返回)。如果等待超时,此函数将返回false。
terminate()终止线程的执行。线程可以立即终止,也可以不立即终止,取决于操作系统的调度策略。在 terminate() 之后使用 QThread::wait() 来确保。
finished()当线程结束时会发出该信号,可以通过该信号来实现线程的清理工作。

使用线程

创建线程的步骤:

  1. 自定义一个类,继承于 QThread,并且只有一个线程处理函数(和主线程不是同一个线程),这个线程处理函数就是重写父类中的 run() 函数。
  2. 线程处理函数里面写入需要执行的复杂数据处理。
  3. 启动线程不能直接调用 run() 函数,需要使用对象来调用 start() 函数实现线程启动。
  4. 线程处理函数执行结束后可以定义一个信号来告诉主线程。
  5. 最后关闭线程。

示例:
创建 Qt 项目,UI界面如下:
在这里插入图片描述

再通过 New File 对话框新建一个 C++ 类,继承于 QThread 类:
在这里插入图片描述
创建结束后会生成文件 mythread.h 和 mythread.cpp。其中 mythread.h:

#ifndef MYTHREAD_H
#define MYTHREAD_H#include <QThread>
#include <QWidget>class MyThread : public QThread
{Q_OBJECT
public:explicit MyThread(QObject *parent = nullptr);void run();//线程任务函数signals://声明信号函数void sendTime(QString Time);
};#endif // MYTHREAD_H

mythread.cpp:

#include "mythread.h"
#include <QTime>
#include <QDebug>MyThread::MyThread(QObject *parent): QThread{parent}
{}void MyThread::run()
{while(1){QString time = QTime::currentTime().toString("hh:mm:ss");qDebug() << time;//发送信号emit sendTime(time);sleep(1);}    
}

widget.h:

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <mythread.h>QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_pushButton_clicked();void showTime(QString Time);private:Ui::Widget *ui;MyThread myThread;
};
#endif // WIDGET_H

widget.cpp:

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);connect(&myThread, &MyThread::sendTime, this, &Widget::showTime);
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()
{myThread.start();
}void Widget::showTime(QString Time)
{ui->label->setText(Time);
}

运行结果:

在这里插入图片描述

线程同步

在多线程程序中,由于存在多个线程,线程之间可能需要访问同一个变量,或一个线程需要等待另一个线程完成某个操作后才产生相应的动作。在 Qt 中实现线程互斥和同步常用的类有:
互斥锁:QMutex、QMutexLocker
条件变量:QWaitCondition
信号量:QSemaphore
读写锁:QReadLocker、QWriteLocker、QReadWriteLock

互斥锁

互斥锁是一种保护和防止多个线程同时访问同一对象实例的方法,在 Qt 中,互斥锁主要是通过 QMutex 类来处理。
QMutex: QMutex 是 Qt 框架提供的互斥锁类,用于保护共享资源的访问,实现线程间的互斥操作。
用途: 在多线程环境下,通过互斥锁来控制对共享数据的访问,确保线程安全。
下面有两个线程,每个线程对 num 进行五万次的加加操作,结果应该是十万:

在这里插入图片描述

但结果显然不是十万,这是因为一个线程对 num 加加后,又被另一个线程写入(num 加加非原子操作,有多步),这就导致前一个线程没有正确加加。这就是多个线程访问同一个变量导致的后果,此时我们通过 QMutex 类对访问变量的操作加锁即可得到正确结果:

在这里插入图片描述

注意:
在这里插入图片描述

这里的 mutex 相当于一把钥匙,如果两个线程要访问同一个共享资源,例如本例的 num,就需要通过 lock() 拿到这把钥匙,然后才可以访问该共享资源,在完成加加操作时,别的线程无法访问 num,就可以正确进行加加,访问完之后还要通过 unlock() 还回钥匙,别的线程才有机会拿到钥匙(才可以访问共享资源)。

QMutexLocker: QMutexLocker 是 QMutex 的辅助类,使用 RAII(Resource Acquisition Is Initialization)方式对互斥锁进行上锁和解锁操作。
用途:简化对互斥锁的上锁和解锁操作,避免忘记解锁导致死锁等问题。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/9197.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微服务(一)

文章目录 项目地址一、微服务1.1 分析User的Domian Verb和Nouns 二、运行docker和k8s2.1 Docker1. 编写dockerfile2. 创建docker image3. 运行docker使用指定端口4. 查看当前运行的镜像5. 停止当前所有运行的docker6. 删除不用的docker images7. 将本地的image上传到hub里 2.2 …

软件架构的演变:从大型机和整体式应用到分布式计算

注&#xff1a;本文为 “软件架构演变” 相关文章合辑。 英文引文机翻&#xff0c;未校。 Evolution of Software Architecture: From Mainframes and Monoliths to Distributed Computing Liv Wong Technical Writer August 06, 2024 Software architecture—the blueprint…

求解旅行商问题的三种精确性建模方法,性能差距巨大

文章目录 旅行商问题介绍三种模型对比求解模型1决策变量目标函数约束条件Python代码 求解模型2决策变量目标函数约束条件Python代码 求解模型3决策变量目标函数约束条件Python代码 三个模型的优势与不足 旅行商问题介绍 旅行商问题 (Traveling Salesman Problem, TSP) 是一个经…

机器学习(三)

一:Logistic Regression(逻辑回归): 1,定义:是一种常用的分类算法&#xff0c;适用于二进制分类问题(binary classification)&#xff0c;输出结果的取值范围为[0,1]&#xff0c;且最终拟合出来的图像是一条S型曲线 2,sigmoid function/logistic function(逻辑函数)&#xff1a…

DFS深度优先搜索

蓝桥杯备赛日记——DFS基础 1.DFS剪枝 OJ2942 数字王国之军训排队 思路 写一个dfs函数&#xff0c;这个dfs函数有两个参数&#xff0c;dep和i&#xff0c;dep表示第dep位同学&#xff0c;i表示打算把所有人分成i支队伍&#xff0c;这个函数的功能是来检测是否能把所有同学分…

C语言自定义数据类型详解(二)——结构体类型(下)

书接上回&#xff0c;前面我们已经给大家介绍了如何去声明和创建一个结构体&#xff0c;如何初始化结构体变量等这些关于结构体的基础知识。下面我们将继续给大家介绍和结构体有关的知识&#xff1a; 今天的主题是&#xff1a;结构体大小的计算并简单了解一下位段的相关知识。…

Niagara学习笔记

橙色 发射器 , 绿色 粒子, 红色 渲染器 Emitter State 发射器状态 Life Cycle Mode&#xff08;生命周期模式&#xff09; 选择Self就是发射器自身管理生命周期 Loop Behavior 决定粒子发射次数 一次&#xff08;Once&#xff09;&#xff1a;发射器只播放一次多次&#…

14-6-3C++STL的list

&#xff08;一&#xff09;list的插入 1.list.insert(pos,elem);//在pos位置插入一个elem元素的拷贝&#xff0c;返回新数据的位置 #include <iostream> #include <list> using namespace std; int main() { list<int> lst; lst.push_back(10); l…

可爱狗狗的404动画页面HTML源码

源码介绍 可爱狗狗的404动画页面HTML源码&#xff0c;源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果 效果预览 源码获取 可爱狗狗的404动画页面HTML源码

C++17 std::variant 详解:概念、用法和实现细节

文章目录 简介基本概念定义和使用std::variant与传统联合体union的区别 多类型值存储示例初始化修改判断variant中对应类型是否有值获取std::variant中的值获取当前使用的type在variant声明中的索引 访问std::variant中的值使用std::get使用std::get_if 错误处理和访问未初始化…

单路由及双路由端口映射指南

远程登录总会遇到登陆不上的情况&#xff0c;可能是访问的大门没有打开哦&#xff0c;下面我们来看看具体是怎么回事&#xff1f; 当软件远程访问时&#xff0c;主机需要两个条件&#xff0c;一是有一个唯一的公网IP地址&#xff08;运营商提供&#xff09;&#xff0c;二是开…

【Elasticsearch】RestClient操作文档

RestClient操作文档 新增文档实体类API语法 查询文档DSL查询 删除文档修改文档批量导入文档小结 新增文档 将数据库中的信息导入elasticsearch中 以商品数据为例 实体类 定义一个索引库结构对应的实体。 Data ApiModel(description "索引库实体") public class …

【项目】基于Qt开发的音乐播放软件

目录 项目介绍 项目概述 界面开发 界面分析 创建工程 主界面布局设计 窗口主框架设计 界面美化 主窗口设定 添加图片资源 head处理 播放控制区处理 自定义控件 BtForm 推荐页面 自定义CommonPage 自定义ListItemBox 自定义MusicSlider 自定义VolumeTool 音…

2025-01-28 - 通用人工智能技术 - RAG - 本地安装 DeepSeek-R1对话系统 - 流雨声

摘要 2025年1月28号 周二&#xff08;除夕&#xff09; 杭州 惠风和畅 小记: 昨天在图书馆整理访谈案例&#xff0c;除了吃饭基本没有停下来直到晚上9点才勉强搞完。每份访谈在3-5万字&#xff0c;总结梳理后每个访谈的字数也在 5000 字左右&#xff0c;接下来如何组织又是一…

电路研究9.2.3——合宙Air780EP中FTP——FTPGET 命令使用方法研究

怎么说呢&#xff0c;之前也是看的&#xff0c;但是也很迷茫&#xff0c;感觉上虽然是对的&#xff0c;但是无法联系到应用里面&#xff0c;今天研究一下FTP 命令使用方法吧。 15.29 使用方法举例 这里发现下面那些看的不懂呢&#xff0c;于是就返回FTP的应用了。 9.5.4 FTP 应…

[A-29]ARMv8/v9-GIC-中断子系统的安全架构设计(Security/FIQ/IRQ)

ver0.1 前言 打开这篇文章的时候,我们已经为每一个中断信号规划一条路径,在外设和PE-Core之间建立了消息通道,外设有紧急的情况下可以给SOC中的大哥打报告了。下面就把接力棒就交到了CPU手里了,但是PE-Core要交给那个Exception Level以及Security下运行的软件处理呢?本文…

PWM频率测量方法

测量PWM&#xff08;脉宽调制&#xff09;信号的频率是嵌入式系统中的常见需求&#xff0c;尤其是在电机控制、LED调光、传感器信号处理等场景中。 在这里介绍两种测量PWM频率的方法&#xff1a;测频法与测周法。 1、测频&#xff08;率&#xff09;法 原理&#xff1a;在闸门…

c++多态

1.多态的概念 通俗来说&#xff0c;就是多种形态&#xff0c;具体点就是去完成某个行为&#xff0c;当不同的对象去完成时会产生出不同 的状态。 2.多态的定义及实现 2.1多态的构成条件 多态是在不同继承关系的类对象&#xff0c;去调用同一函数&#xff0c;产生了不同的行为…

MySQL分表自动化创建的实现方案(存储过程、事件调度器)

《MySQL 新年度自动分表创建项目方案》 一、项目目的 在数据库应用场景中&#xff0c;随着数据量的不断增长&#xff0c;单表存储数据可能会面临性能瓶颈&#xff0c;例如查询、插入、更新等操作的效率会逐渐降低。分表是一种有效的优化策略&#xff0c;它将数据分散存储在多…

Deepseek的RL算法GRPO解读

在本文中&#xff0c;我们将深入探讨Deepseek采用的策略优化方法GRPO&#xff0c;并顺带介绍一些强化学习&#xff08;Reinforcement Learning, RL&#xff09;的基础知识&#xff0c;包括PPO等关键概念。 策略函数&#xff08;policy&#xff09; 在强化学习中&#xff0c; a…