【QT】线程控制和同步

目录

概述

QThread常用API

线程使用

创建一个QThread的子类

主线程启动线程

线程安全

互斥锁

QMutex

使用示例:两个线程一个共享静态变量进行++

线程子类创建

主线程调用

QMutexLocker

条件变量 

信号量 


概述

  • 在 Qt 中,多线程的处理⼀般是通过 QThread类 来实现。
  • QThread 代表⼀个在应⽤程序中可以独⽴控制的线程,也可以和进程中的其他线程共享数据。
  • QThread 对象管理程序中的⼀个控制线程。

        QThread要想创建线程,就需要创建出这样类的实例,创建线程的时候,需要重点指定线程的入口函数,创建一个QThread的子类,重写其中的run函数,起到指定入口函数的方式。 

QThread常用API

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

线程使用

        由于存在线程安全的问题,多个线程同时对于界面的状态进行修改,此时就会导致界面出错了,因此在qt中,多线程内部不允许对界面的控件状态进行修改,只能在主线程中进行修改。

创建一个QThread的子类

thread.h

#ifndef THREAD_H
#define THREAD_H
#include <QThread>
#include <QWidget>class Thread : public QThread
{Q_OBJECT
public:Thread();void run();
signals:void notify();
};#endif // THREAD_H

thread.cpp

#include "thread.h"Thread::Thread()
{}void Thread::run()
{for(int i = 0 ; i < 10; i++){sleep(1);emit notify();}
}

主线程启动线程

widget.h

#ifndef WIDGET_H
#define WIDGET_H
#include "thread.h"
#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void handle();
private:Ui::Widget *ui;Thread thread;
};
#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(&thread,&Thread::notify,this,&Widget::handle);thread.start();
}Widget::~Widget()
{delete ui;
}void Widget::handle()
{int value = ui->lcdNumber->intValue();ui->lcdNumber->display(--value);
}

        客户端中的多线程,主要用于通过多线程的方式,执行一些耗时的等待IO的操作,避免主线程被卡死,比如当用户需要上传/下载一个很大的文件,我们可以使用单独的线程,来处理这种密集的IO操作,要挂起也是挂起这个新的线程,主线程负责事件循环,负责处理用户的各种操作。

线程安全

实现线程互斥和同步常⽤的类有:
  • 互斥锁:QMutex、QMutexLocker
  • 条件变量:QWaitCondition
  • 信号量:QSemaphore
  • 读写锁:QReadLocker、QWriteLocker、QReadWriteLock

互斥锁

        互斥锁是⼀种保护和防⽌多个线程同时访问同⼀对象实例的⽅法,在 Qt 中,互斥锁主要是通过 QMutex类来处理。QMutex中lock加锁,unlock解锁。

QMutex

特点:QMutex 是 Qt 框架提供的互斥锁类,⽤于保护共享资源的访问,实现线程间的互斥操作。
⽤途:在多线程环境下,通过互斥锁来控制对共享数据的访问,确保线程安全。

使用示例:两个线程一个共享静态变量进行++

线程子类创建

thread.h

#ifndef THREAD_H
#define THREAD_H
#include <QThread>
#include <QWidget>
#include <QMutex>
class Thread : public QThread
{Q_OBJECT
public:Thread();void run();//共享资源static int num;//创建一把锁QMutex mutex;
signals:void notify();
};#endif // THREAD_H

thread.cpp

#include "thread.h"int Thread::num=0;
Thread::Thread()
{}void Thread::run()
{for(int i = 0 ; i < 10; i++){mutex.lock();num++;mutex.unlock();}
}
主线程调用
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);Thread::num=0;Thread t1,t2;t1.start();t2.start();//让主线程等待两个线程执行完毕t1.wait();t2.wait();qDebug()<<Thread::num;
}Widget::~Widget()
{delete ui;
}

QMutexLocker

上述的代码中,在获取到锁后,执行我们指定的逻辑,一旦发生错误,或者异常将会导致锁未释放,因此我们需要引入 QMutexLocker locker(&mutex);

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

代码示例: 

void Thread::run()
{for(int i = 0 ; i < 10; i++){QMutexLocker locker(&mutex); //在作⽤域内⾃动上锁num++;}//在作⽤域结束时⾃动解锁
}

此外还有QReadWriteLocker、QReadLocker、QWriteLocker

特点:

  • QReadWriteLock 是读写锁类,⽤于控制读和写的并发访问。
  • QReadLocker ⽤于读操作上锁,允许多个线程同时读取共享资源。
  • QWriteLocker ⽤于写操作上锁,只允许⼀个线程写⼊共享资源。
  • ⽤途:在某些情况下,多个线程可以同时读取共享数据,但只有⼀个线程能够进⾏写操作。读写锁提 供了更⾼效的并发访问⽅式。

条件变量 

在多线程编程中,假设除了等待操作系统正在执⾏的线程之外,某个线程还必须等待某些条件满⾜才能执⾏,这时就会出现问题。这种情况下,线程会很⾃然地使⽤锁的机制来阻塞其他线程,因为这只是线程的轮流使⽤,并且该线程等待某些特定条件,⼈们会认为需要等待条件的线程,在释放互斥锁或读写锁之后进⼊了睡眠状态,这样其他线程就可以继续运⾏。当条件满⾜时,等待条件的线程将被另⼀个线程唤醒。
在 Qt 中,专⻔提供了 QWaitCondition类 来解决像上述这样的问题。
  • 特点:QWaitCondition 是 Qt 框架提供的条件变量类,⽤于线程之间的消息通信和同步。
  • ⽤途:在某个条件满⾜时等待或唤醒线程,⽤于线程的同步和协调

也就是说多个线程之间的调度是无序的,为了能够一定程度的干预线程之间的执行顺序,需要引入条件变量。

QMutex mutex;
QWaitCondition condition;
// 在等待线程中
mutex. lock ();
// 检查条件是否满⾜,若不满⾜则等待
while (! conditionFullfilled ())
{
        condition. wait (&mutex); // 等待条件满⾜并释放锁
}
// 条件满⾜后继续执⾏
//...
mutex. unlock ();
// 在改变条件的线程中
mutex. lock ();
// 改变条件
changeCondition ();
condition. wakeAll (); // 唤醒等待的线程
mutex. unlock ();

信号量 

有时在多线程编程中,需要确保多个线程可以相应的访问⼀个数量有限的相同资源。例如,运⾏程序 的设备可能是⾮常有限的内存,因此我们更希望需要⼤量内存的线程将这⼀事实考虑在内,并根据可 ⽤的内存数量进⾏相关操作,多线程编程中类似问题通常⽤信号量来处理。信号量类似于增强的互斥锁,不仅能完成上锁和解锁操作,⽽且可以跟踪可⽤资源的数量。
  • 特点:QSemaphore 是 Qt 框架提供的计数信号量类,⽤于控制同时访问共享资源的线程数量。
  • ⽤途:限制并发线程数量,⽤于解决⼀些资源有限的问题。

QSemaphore semaphore ( 2 ); // 同时允许两个线程访问共享资源
// 在需要访问共享资源的线程中
semaphore. acquire (); // 尝试获取信号量,若已满则阻塞
// 访问共享资源
//...
semaphore. release (); // 释放信号量
// 在另⼀个线程中进⾏类似操作

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

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

相关文章

【CSS in Depth 2 精译_020】3.3 元素的高度

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一章 层叠、优先级与继承&#xff08;已完结&#xff09; 1.1 层叠1.2 继承1.3 特殊值1.4 简写属性1.5 CSS 渐进式增强技术1.6 本章小结 第二章 相对单位&#xff08;已完结&#xff09; 2.1 相对…

【proteus经典实战】定时器控制交通灯指示灯

一、简介 基于8051系列单片机实现&#xff0c;旨在模拟一个简单的交通灯系统&#xff0c;实现红、黄、绿灯的交替亮灭。使用了特殊功能寄存器&#xff08;SFR&#xff09;和位操作来控制硬件&#xff0c;使用定时器0的中断功能来控制交通灯信号的切换。通过软件控制&#xff0…

解决selenium打印保存为PDF时图片未加载成功的问题

使用selenium打印网页时&#xff0c;如果程序运行很快的话&#xff0c;可能会导致图片没有加载成功即进行了保存&#xff0c;出现这个问题最初的思考是在执行打印任务时使用js进行强制等待&#xff0c;后发现实现效果并不好。在加载页面时使用自动下滑的方式将网页拉到底&#…

uniapp动态计算并设置元素高度

<template><view><scroll-view id"sv-box" :scroll-y"true" :style"{height:navHeightpx}"></scroll-view><view id"btn-box"><button>取消</button><button>确认</button><…

Linux Vim教程(三):插入模式与命令模式

目录 1. Vim的基本模式介绍 2. 插入模式 2.1 进入插入模式 2.2 退出插入模式 2.3 插入模式下的快捷键 2.4 插入模式中的光标移动 3. 命令模式 3.1 进入命令模式 3.2 常用命令 3.3 搜索和替换 3.4 其他有用的命令 3.5 配置与优化 3.5.1 自动补全 3.5.2 自定义快捷…

【前后端联调】HttpMessageNotReadableException

【前后端联调】HttpMessageNotReadableException 01 问题描述 在前后端联调时产生的问题&#xff0c;关键是下面这句翻译JSON解析错误&#xff1a;无法构造“java.util.ArrayList”的实例 org.springframework.http.converter.HttpMessageNotReadableException: JSON parse …

记录贴-NGINX相关

链接: NGINX相关配置信息说明

在 CI/CD 中怎么使用 Docker 部署前端项目?

本项目代码已开源&#xff0c;具体见&#xff1a; 前端工程&#xff1a;vue3-ts-blog-frontend 后端工程&#xff1a;express-blog-backend 数据库初始化脚本&#xff1a;关注公众号程序员白彬&#xff0c;回复关键字“博客数据库脚本”&#xff0c;即可获取。 前言 在上一篇文…

Web Pages 表单

Web Pages 表单 介绍 Web pages 表单是现代网页设计中不可或缺的组成部分&#xff0c;它们允许用户与网站进行交互&#xff0c;提交信息&#xff0c;如注册、登录、反馈、预订等。表单的设计和功能对用户体验和网站的业务目标有着直接的影响。本文将深入探讨Web pages表单的各…

快速上手AI指令:打造个性化智能交互体验的全面指南

快速上手AI指令&#xff1a;打造个性化智能交互体验的全面指南 一、初识文心一言1.1 文心一言简介1.2 文心一言的特点 二、准备工作2.1 获取访问权限2.2 熟悉界面布局2.3 了解基础指令 三、基础指令操作3.1 问答互动3.2 文本创作3.3 任务规划 四、进阶指令操作4.1 复杂查询4.2 …

Python酷库之旅-第三方库Pandas(035)

目录 一、用法精讲 106、pandas.Series.iloc方法 106-1、语法 106-2、参数 106-3、功能 106-4、返回值 106-5、说明 106-6、用法 106-6-1、数据准备 106-6-2、代码示例 106-6-3、结果输出 107、pandas.Series.__iter__魔法方法 107-1、语法 107-2、参数 107-3、…

Java程序的故障排查

文章目录 Linux命令关机/重启/注销系统信息和性能查看磁盘和分区⽤户和⽤户组⽹络和进程管理常⻅系统服务命令⽂件和⽬录操作⽂件查看和处理打包和解压RPM包管理命令YUM包管理命令DPKG包管理命令APT软件⼯具 JDK命令jpsjstatjinfojmapjhatjstackjcmdjconsole 分析工具VisualVME…

ios 设置行距和获取文本行数

设置文本行距 UILabel *label [[UILabel alloc] init];label.font [UIFont systemFontOfSize:12];label.numberOfLines 0;label.lineBreakMode NSLineBreakByWordWrapping;label.textColor [UIColor colorWithHexString:"B3B3B3"];label.text textDes;//设置行…

blender和3dmax和maya和c4d比较

Blender、3ds Max、Maya和Cinema 4D (C4D)都是强大的3D建模和动画软件&#xff0c;但它们各有特点和适用领域。以下是它们的比较&#xff1a; Blender: 开源免费全面的功能&#xff0c;包括建模、动画、渲染、视频编辑等学习曲线较陡峭&#xff0c;但社区支持强大适合独立艺术家…

自动驾驶-预测概览

通过生成一条路径来预测一个物体的行为&#xff0c;在每一个时间段内&#xff0c;为每一辆汽车重新计算预测他们新生成的路径&#xff0c;这些预测路径为规划阶段做出决策提供了必要信息 预测路径有实时性的要求&#xff0c;预测模块能够学习新的行为。我们可以使用多源的数据…

超简单安装指定版本的clickhouse

超简单安装指定版本的clickhouse 命令执行shell脚本 idea连接 命令执行 参考官网 # 下载脚本 wget https://raw.githubusercontent.com/183461750/doc-record/d988dced891d70b23c153a3bbfecee67902a3757/middleware/data/clickhouse/clickhouse-install.sh # 执行安装脚本(中…

【漏洞复现】Netgear WN604 downloadFile.php 信息泄露漏洞(CVE-2024-6646)

0x01 产品简介 NETGEAR WN604是一款由NETGEAR&#xff08;网件&#xff09;公司生产的无线接入器&#xff08;或无线路由器&#xff09;提供Wi-Fi保护协议&#xff08;WPA2-PSK, WPA-PSK&#xff09;&#xff0c;以及有线等效加密&#xff08;WEP&#xff09;64位、128位和152…

机器学习 -逻辑回归的似然函数

公式解释 公式如下&#xff1a; L ( θ ) ∏ i 1 m P ( y i ∣ x i ; θ ) ∏ i 1 m ( h θ ( x i ) ) y i ( 1 − h θ ( x i ) ) 1 − y i L(\theta) \prod_{i1}^m P(y_i | x_i; \theta) \prod_{i1}^m (h_\theta(x_i))^{y_i} (1 - h_\theta(x_i))^{1 - y_i} L(θ)i1∏…

亲测--linux下安装ffmpeg最新版本---详细教程

下载地址 Download FFmpeg 下载最新的https://ffmpeg.org/releases/ffmpeg-7.0.1.tar.xz 上传到服务器 解压 tar xvf ffmpeg-7.0.1.tar.xz 编译 cd ffmpeg-7.0.1 ./configure --prefix=/usr/local/ffmpeg make && make install 报错: 解决:在后面加 跳过检测…

上海市计算机学会竞赛平台2022年9月月赛丙组二叉树的遍历

题目描述 有一棵二叉树&#xff0c;结点数量不超过 2626 个&#xff0c;树上的每个结点都有一个大写字母。 给定这棵二叉树的前序遍历及中序遍历&#xff0c;请输出它的后序遍历。 输入格式 第一行&#xff1a;一个字符串&#xff0c;表示二叉树的前序遍历&#xff1b;第二…