C++多线程学习[四]:多线程的通信和同步、互斥锁、超时锁、共享锁

一、多线程的状态

  • 初始化 (Init):该线程正在被创建。
  • 就绪 (Ready):该线程在就绪列表中,等待CPU的调度。
  • 运行 (Running):该线程正在运行。
  • 阻塞(Blocked):该线程被阻塞挂起。Blocked状态包括:pend(锁、事件、信号量等阻塞)、suspend(主动pend)、delay(延时阻塞)、pendtime(因为锁、事件、信号量时间等超时等待)。
  • 退出(Exit):该线程运行结束,等待父线程后收其控制块资源。

在这里插入图片描述

二、多线程之间的竞争关系和临界区

1、竞争关系(Race condition)

多个线程同时读写共享资源
例如:

#include<iostream>
#include<thread>
#include<string>
using namespace std;
void Test()
{cout << "---------------" << endl;cout << "Test 1 " << endl;cout << "Test 2 " << endl;cout << "-----------------" << endl;
}int main()
{for (int i = 0; i < 10; i++){thread th(Test);th.detach();}getchar();return 0;
}

在这里插入图片描述

我们创建了10个线程,但是每个线程在运行时都是无规律的,对于相同的输出都是处于竞争状态。

2、临界区(Critical Section)

我们使用C++ 11 自带的mutex(互斥锁)来解决竞争状态。
在这里插入图片描述
原理:
当n个线程要访问我们临界区时,只允许一个线程进入,其余线程会阻塞在临界区外,每当一个线程运行完临界区代码后,会允许阻塞在临界区外的一个线程再次访问临界区。

3、lock()和try_lock()区别

  • lock():**lock 函数用于获取互斥锁。**如果当前互斥锁已被其他线程占用,则 lock 函数将阻塞当前线程,直到互斥锁可用为止。一旦成功获取到互斥锁,该线程将独占互斥锁,并可以继续执行后续的操作。在完成互斥锁所需的操作后,线程应该调用 unlock 函数来释放互斥锁,以便其他线程可以获取它。阻塞式的,会一直等待直到成功获取到互斥锁。

  • try_lock()try_lock 函数用于尝试获取互斥锁,但是它并不会阻塞当前线程。如果当前互斥锁可用,try_lock 函数将立即获取到互斥锁,并返回 true。如果当前互斥锁被其他线程占用,try_lock 函数将立即返回 false,而不会阻塞线程。通过检查返回值,线程可以根据情况选择等待或放弃获取互斥锁。非阻塞式的,立即返回获取互斥锁的结果,线程可以根据返回值做出相应的处理。
    例如:这里有10个线程,只有两个线程进入,而其它8个线程并不会阻塞住。
    在这里插入图片描述

  • 使用 lock 函数时要注意避免死锁的情况,而 try_lock 函数则可以更灵活地处理互斥锁的获取失败情况。

4、互斥锁的坑(线程抢占)

在这里插入图片描述
可以看到在这段代码中,本来1号线程运行完,执行unlock()后,应该其他阻塞的线程应该进入代码内,但是发现进入的依旧是1号ID的线程。
原因:当我们执行完unlock()后,因为代码执行速度就几微秒的时间,但是我们CPU调度探测一次得过一段时间,所以导致了这个问题。(也就是说我们执行的速度快于检测的速度,导致我们线程1号执行完后又再次进入循环,又把资源锁上了)
解决:只需要在unlock()后面等待一段时间就可以,让我们CPU有充裕的时间来调度检测。在这里插入图片描述

三、互斥锁(mutex)

上面样例中设计到这里就不在过多描述

四、超时锁(timed_mutex)

在这里插入图片描述
在这里插入图片描述

超时锁可以让阻塞的线程不断尝试进入,如果超过等待时间,就会执行日志结果,可以帮助我们更好的检查线程状态,检查是否超时或者是否存在死锁。

五、可重入锁(recursive_mutex)

1.可重入锁可以解决哪类情况?

如果直接用互斥锁在这里插入图片描述
显然会直接报错,因为我们要进入下一个锁内需要先解除当前锁在这里插入图片描述

显然是让人头疼麻烦的,我们必须每次得考虑解锁的时机。为了解决此类情况,我们有了可重入锁。

2.可重入锁。

在这里插入图片描述
功能如可以多重进入锁区域,要注意的是,进入几个锁就要在最后解除几个锁,这样才能让其他阻塞线程进入。

六、共享锁(shared_mutex)

C++ 14中引入了shared_timed_mutex;
C++ 17中引入了shared_mutex;

1、 共享锁的功能

假设有6个线程同时要访问同一片区域数据,有5个线程要读数据,而有一个线程要写数据,那么共享锁可以让读线程的5个线程同时进行读,然后阻塞写数据的线程。当写线程进入时,阻塞5个读的线程,写线程开始写数据。这就是共享锁的基本作用。

2、代码

#include<iostream>
#include<thread>
#include<shared_mutex>
using namespace std;
shared_mutex smux;
int num;
void thread_read(int i)
{for (;;){smux.lock_shared();cout << "num is :" <<num<< endl;this_thread::sleep_for(1000ms);smux.unlock_shared();this_thread::sleep_for(10ms);}
}
void thread_write(int i)
{for (;;){smux.lock_shared();num++;cout << "add num" << endl;this_thread::sleep_for(1000ms);smux.unlock_shared();this_thread::sleep_for(10ms);}}int main()
{for (int i = 0; i < 5; i++){thread th(thread_read,i + 1);this_thread::sleep_for(50ms);th.detach();}for (int i = 0; i < 2; i++){thread th(thread_write, i + 1);this_thread::sleep_for(50ms);th.detach();}getchar();return 0;
}

在这里插入图片描述

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

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

相关文章

**登录+JWT+异常处理+拦截器+ThreadLocal-开发思想与代码实现**

用户登录——>数据加密数据库比对——>生成jwt令牌封装返回——>拦截器统一拦截进行jwt校验-并将数据放入本地线程中。 0、 ThreadLocal 介绍&#xff1a; ThreadLocal 并不是一个Thread&#xff0c;而是Thread的线程局部变量。 ThreadLocal为每个线程提供单独一份…

边缘计算的挑战和机遇

目录 前言 一、边缘计算 &#xff08;一&#xff09;为什么需要边缘计算 &#xff08;二&#xff09;什么是边缘计算 &#xff08;三&#xff09;边缘计算体系架构 &#xff08;四&#xff09;边缘计算的好处 二、案例分析 &#xff08;一&#xff09;云卸载 &#xf…

三个视频提取软件一键快速提取

在当今的社交媒体时代&#xff0c;短视频分享已经成为一种流行的表达方式。然而&#xff0c;有时我们遇到视频过长或水印影响观看体验的情况。这时&#xff0c;一款快速、高效的短视频提取软件就显得尤为重要。今天&#xff0c;我们就为大家推荐三款优秀的短视频提取软件。 水…

【MATLAB】Linux版本 高分辨率屏 调整显示缩放

0 引言 安装了linux版本的MATLAB R2023b之后&#xff0c;发现工具栏字体很小不方便使用&#xff0c;所以上网找到了MATLAB论坛上某位大佬的教程&#xff1a;参考链接&#xff0c;放在这里供各位参考 。 1 环境 这里注明我的matlab安装环境仅供参考&#xff0c;未在其他环境下…

高级RAG技术、以及算法实现

知识库地址&#xff1a;Advanced RAG techniques 检索增强生成&#xff08;Retrieval Augmented Generation, RAG&#xff09;为大语言模型&#xff08;Large Language Model, LLM&#xff09;提供了一种机制&#xff0c;通过从数据源检索到的信息为其生成的答案提供依据。简而…

【VTKExamples::PolyData】第四期 DijkstraGraphGeodesicPath

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 前言 本文分享VTK样例DijkstraGraphGeodesicPath,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的动力(^U^)ノ~YO 1. DijkstraGraphGeodesicPath /…

【期末不挂科-C++考前速过系列P1】大二C++第1次过程考核(3道简述题&7道代码题)【解析,注释】

前言 大家好吖&#xff0c;欢迎来到 YY 滴C复习系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的《Lin…

把屏幕变成毫米测量工具

主要功能&#xff1a; 根据屏幕的像素个数和物理长度对应关系&#xff0c;计算设置的实际长度&#xff0c;把屏幕当成直尺用。功能模仿FastStone里面的屏幕标尺工具 运行演示&#xff1a; 其他说明&#xff1a; 1.软件打开时会自动获取屏幕像素个数和物理长度&#xff0c;也可…

基于爬虫和Kettle的豆瓣电影的采集与预处理

一&#xff1a;爬虫 1、爬取的目标 将豆瓣电影网上的电影的基本信息&#xff0c;比如&#xff1a;电影名称、导演、电影类型、国家、上映年份、评分、评论人数爬取出来&#xff0c;并将爬取的结果放入csv文件中&#xff0c;方便存储。 2、网站结构 图1豆瓣网网站结构详…

Parallel patterns: convolution —— An introduction to stencil computation

在接下来的几章中&#xff0c;我们将讨论一组重要的并行计算模式。这些模式是许多并行应用中出现的广泛并行算法的基础。我们将从卷积开始&#xff0c;这是一种流行的阵列操作&#xff0c;以各种形式用于信号处理、数字记录、图像处理、视频处理和计算机视觉。在这些应用领域&a…

尚硅谷离线数仓之采集平台

1. 用户行为日志 数据流向流程图如下&#xff0c;其中红框表示用户行为日志数据的流向图。 1.1 行为日志内容 行为日志主要包括以下几个内容 页面浏览记录动作记录曝光记录启动记录错误记录 页面浏览记录 动作记录 曝光记录 启动记录 1.2 用户行为日志格式 页面日志启动…

Radzen Blazor Studio 脚手架框架解读

背景 组织管理管理准备使用Blazor这个工具实现&#xff0c;因为其有对应的 scaffold 脚手架&#xff0c;先构建数据库&#xff0c;然后通过向导&#xff0c;生成CRUD以及对应的接口&#xff0c;那么有必要看一下&#xff0c;其内部的代码结构是什么样的。 结构 接口层 有两类…

STM32-04-STM32时钟树

STM32时钟树 什么是时钟&#xff1f; 时钟是具有周期性的脉冲信号&#xff0c;最常用的是占空比50%的方波。&#xff08;时钟是单片机的脉搏&#xff0c;搞懂时钟走向及关系&#xff0c;对单片机使用至关重要&#xff09;。 时钟树 时钟源 2个外部时钟源 高速外部振荡器(HSE…

vue中el-radio无法默认选中

页面上不生效&#xff0c;默认什么都不选中 <el-radio-group v-model"queryParams.videoUrlType"><el-radio :label"1">本地上传</el-radio><el-radio :label"2">外部链接</el-radio> </el-radio-group>da…

vue el-table最后一页所有数据批量删除或者单个删除,自动回到上一页,包括单条删除

批量删除单条删除//判断数据是否可以满一页isFillList () {const totalPage Math.ceil((this.docDateTotal - this.changeDocData.length) / this.docPageSize) // 总页数this.docPage this.docPage > totalPage ? totalPage : this.docPagethis.docPage this.docPage &…

高级 Python 面试问题与解答

文章目录 专栏导读1.什么是PIP&#xff1f;2.什么是 zip 函数&#xff1f;3.Python 中的 __init __ () 是什么&#xff1f;4.Python 中的访问说明符是什么&#xff1f;5.Python 中的单元测试是什么&#xff1f;6.Python全局解释器锁&#xff08;GIL&#xff09;&#xff1f;7.P…

docker-consul部署

目录 一、环境 二、consul服务器 三、registrator服务器 四、consul-template 一、环境 consul服务器 192.168.246.10 运行consul服务、nginx服务、consul-template守护进程 registrator服务器 192.168.246.11 运行registrator容器、运行ngi…

看完这篇你就知道了!人气爆表的6款Sketch插件大揭秘!

Sketch作为一种在线设计工具&#xff0c;一直是许多设计师的最爱。它不仅能快速建立原型&#xff0c;还能提供丰富的插件&#xff0c;以满足不同的需求。 今天&#xff0c;小抄将与大家分享6款流行的Sketch插件供参考。这些插件都是小抄精心挑选的&#xff0c;支持Windows、Ma…

flink1.14.5使用CDH6.3.2的yarn提交作业

使用CDH6.3.2安装了hadoop集群&#xff0c;但是CDH不支持flink的安装&#xff0c;网上有CDH集成flink的文章&#xff0c;大都比较麻烦&#xff1b;但其实我们只需要把flink的作业提交到yarn集群即可&#xff0c;接下来以CDH yarn为基础&#xff0c;flink on yarn模式的配置步骤…

React18-树形菜单-递归

文章目录 案例分析技巧通信展示效果实现代码技巧点技巧点 Refer to 案例分析 https://github.com/dL-hx/manager-fe/commit/85faf3b1ae9a925513583feb02b9a1c87fb462f7 从接口获取城市数据,渲染出一个树形菜单 要求: 可以展开和收起 技巧 学会递归渲染出一个树形菜单, 并点击后…