线程的同步互斥

 互斥

互斥保证了在一个时间内只有一个线程访问一个资源。

先看一段代码:三个线程同时对全局变量val进行--,同时val每自减一次其线程局部存储的全局变量++

#include <iostream>
#include <thread>
#include <vector>
#include <unistd.h>
#define NUM 3//线程数量
using namespace std;int val = 10;
__thread int t_val = 0;void fun(string name)
{while(1){if(val > 0){usleep(10000);cout << name << " get one" << " total: " << t_val << " val: " << val <<endl;val--;t_val++;}else {break;}}}int main()
{thread trd[NUM];//创建多个线程for(int i = 0; i < NUM; i++){string name = "thread" + to_string(i+1);trd[i] = thread(fun, name);}//等待线程for(int i = 0; i < NUM; i++){trd[i].join();}return 0;
}

最终的结果val竟然出现了负数,为什么呢?

因为线程函数的操作是非原子的,线程可能在任何一步被切换。这就会导致数据不一致问题,要想解决就必须使用锁。

锁——mutex

mutex是无参构造, 不支持拷贝构造。

两个无参接口,用来加锁和解锁 

#include <iostream>
#include <unistd.h>
#include <thread>
#include <vector>
#include <mutex>
#define NUM 3 // 线程数量
using namespace std;int val = 10;
thread_local int t_val = 0;
mutex mut;void fun(string name)
{while (1){{mut.lock();if (val > 0){usleep(10000);t_val++;val--;cout << name << " get one" << " total: " << t_val << " val: " << val << endl;mut.unlock();}else{mut.unlock();break;}}usleep(2);}
}int main()
{thread trd[NUM];// 创建多个线程for (int i = 0; i < NUM; i++){string name = "thread" + to_string(i + 1);trd[i] = thread(fun, name);}// 等待线程for (int i = 0; i < NUM; i++){trd[i].join();}return 0;
}

加锁保证锁内资源的数据安全性,是一种用时间换取安全的方式。锁在任何时候只能被一个线程申请,那么临界资源就只能被一个线程使用和修改,保证了数据一致性。

锁的分配也要合理,不然会导致线程的饥饿问题。如果线程在释放锁后立马申请锁就会导致其他线程无法获取锁

锁的原理

lock不是原子的,先将立即数0放到寄存器中,再将寄存器内容和内存中的mutex内容交换,最后判断寄存器内容。虽然lock不是原子的,不过即使发生进程切换,也不会发生错误。

锁未被申请时,mutex值为1。被申请后会将1传递到寄存器中,所以锁就是一种传递,哪个线程传递1到寄存器就可以执行

unlock是原子的,将mutex值置为1。

同步

同步可以在数据安全的情况下,让线程按照特定的顺序访问临界资源。

条件变量——condition_variable

 wait 可以让线程停止并等待通知,直到其他线程用notify接口发出通知,线程才会被唤醒。

使用 wait 必须搭配 std::unique_lock<std::mutex> 一起使用 

notify_one:通知一个正在等待的线程 

notify_all:通知所有正在等待的线程

例子:

通过等待,判断临界资源是否准备就绪,决定线程是否继续执行。

#include <iostream>
#include <mutex>
#include <condition_variable>
#include <thread>
#include <unistd.h>using namespace std;
mutex m;
condition_variable cond;
bool flag = false;void fun()
{unique_lock<mutex> ul(m);cout << "已加锁,即将等待" << endl;while(flag != true){cond.wait(ul);cout << "结束等待,判断flag条件" << endl;}cout << "执行任务。。。" << endl;
}int main()
{thread th(fun);sleep(1);cond.notify_one();sleep(1);flag = true;cond.notify_one();th.join();cout << "end" << endl;return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Java之Java基础十六(反射)

一、什么是反射 一般情况下&#xff0c;我们在使用某个类之前已经确定它到底是个什么类了&#xff0c;拿到手就直接可以使用 new 关键字来调用构造方法进行初始化&#xff0c;之后使用这个类的对象来进行操作。 Writer writer new Writer(); writer.setName("aaa"…

WPF的MVVM架构:如何通过数据绑定简化UI逻辑

WPF的MVVM架构&#xff1a;如何通过数据绑定简化UI逻辑 目录 MVVM模式概述数据绑定在MVVM中的作用实现MVVM模式的步骤MVVM模式中的常见问题与解决方案实践示例总结 MVVM模式概述 MVVM&#xff08;Model-View-ViewModel&#xff09;是一种设计模式&#xff0c;用于WPF应用程序…

超声波传感器 - 从零开始认识各种传感器【第十九期】

超声波传感器|从零开始认识各种传感器 1、什么是超声波传感器 超声波传感器是一种利用超声波来进行距离测量和目标检测的传感器。它通过发送&#xff0c;超声波脉冲&#xff0c;并测量超声波从传感器发射到目标物体并返回的时间来计算目标物体与传感器之间的距离。 超声波传感…

echarts无数据的展示内容,用graphic属性配置

echarts无数据的展示内容&#xff0c;用graphic属性配置 当echarts无数据的时候&#xff0c;图表展示的是个空白部分&#xff0c;感觉会有点丑&#xff0c;影响页面美观&#xff0c;这时候翻阅了echarts的官网&#xff0c;让我找到个配置项&#xff0c;试试发现还可以&#xf…

Notion支持直接绑定自己的域名,有何工具可替代为公开网站自定义域名?

Notion最近大招频出&#xff0c;推出新功能——自定义域名。只需简单几步&#xff0c;xxx.notion.site秒变你的专属域名&#xff08;月费仅需10美金&#xff09;。推特上的独立内容创作者/初创公司&#xff0c;用它来打造品牌、分享资料模板&#xff0c;甚至实现盈利。 Notion的…

你还在为PDF转Word烦恼?试试这四款免费工具吧!

悄咪咪问一句&#xff0c;大家在平时上班时最头疼的事情有哪些&#xff1f;我想会有很多朋友也有pdf如何在线转换word文档的免费方式&#xff0c;毕竟这些办公文档是非常常见的问题了&#xff0c;所以今天就专门准备这么一篇文章来分享我个人喜欢的四款好用工具&#xff1a; 第…

做知识付费项目还能做吗?知识付费副业项目如何做?能挣多少钱?

hello,我是阿磊&#xff0c;一个20年的码农&#xff0c;6年前代码写不动了&#xff0c;转型专职做副业项目研究&#xff0c;为劳苦大众深度挖掘互联网副业项目&#xff0c;共同富裕。 现在做知识付费项目还能做吗&#xff1f; 互联网虚拟资源项目我一直在做&#xff0c;做了有…

【单片机毕业设计选题24088】-基于STM32的智能家居控制系统

系统功能: 系统操作说明&#xff1a; 上电后OLED显示 “欢迎使用智能家居系统请稍后”&#xff0c;两秒后显示Connecting...表示 正在连接阿里云&#xff0c;正常连接阿里云后显示第一页面&#xff0c;如长时间显示Connecting...请 检查WiFi网络是否正确。 第一页面第一行…

使用runlink通过容器打印出容器的启动命令

1、Runlike简介 Runlike:通过容器打印出容器的启动命令&#xff0c;然后发现自己需要手动重新运行一些容器的人来说&#xff0c;这是一个真正的节省时间。 2、Docker镜像安装 2.1 构建Runlike容器 [rootlocalhost ~]# docker run --rm -v /var/run/docker.sock:/var/run/do…

嵌入式Linux:符号链接(软链接)和硬链接

目录 1、符号链接&#xff08;软链接&#xff09; 2、硬链接 3、link()函数 4、symlink()函数 5、readlink()函数 在 Linux 系统中&#xff0c;符号链接&#xff08;软链接&#xff09;和硬链接是两种创建文件链接的方法。理解它们的区别和使用场景对于文件系统的管理非常…

Spring核心机制Ioc和Aop

Spring全家桶 WEB&#xff1a;SpringMvc、Spring Web Flux 持久层&#xff1a;Spring Data、Spring Data Redis、Spring Data MongoDB 安全校验&#xff1a;spring Security 构建工程脚手架&#xff1a;SpringBoot 微服务&#xff1a;SpringCloud 所有的Spring框架集成&#xf…

轻松入门Linux—CentOS,直接拿捏 —/— <1>

一、什么是Linux Linux是一个开源的操作系统&#xff0c;目前是市面上占有率极高的服务器操作系统&#xff0c;目前其分支有很多。是一个基于 POSIX 和 UNIX 的多用户、多任务、支持多线程和多 CPU 的操作系统 Linux能运行主要的UNIX工具软件、应用程序和网络协议 Linux支持 32…

每日OJ_牛客CM26 二进制插入

目录 牛客CM26 二进制插入 解析代码 牛客CM26 二进制插入 二进制插入_牛客题霸_牛客网 解析代码 m:1024&#xff1a;100000000 00 n:19 &#xff1a; 10011 要把n的二进制值插入m的第j位到第i位&#xff0c;只需要把n先左移j位&#xff0c;然后再进行或运算&#xff08;|&am…

ctfshow 权限维持 web670--web679

web670 <?php// 题目说明&#xff1a; // 想办法维持权限&#xff0c;确定无误后提交check&#xff0c;通过check后&#xff0c;才会生成flag&#xff0c;此前flag不存在error_reporting(0); highlight_file(__FILE__);$a$_GET[action];switch($a){case cmd:eval($_POST[c…

OCC BRepOffsetAPI_ThruSections使用

目录 一、BRepOffsetAPI_ThruSections简介 二、功能与特点 三、应用场景 四、示例 一、BRepOffsetAPI_ThruSections简介 在Open CASCADE Technology (OCCT) 中,BRepOffsetAPI_ThruSections 类是用来通过放样生成一个实体或者一个面壳(Shell)。当使用这个类时,isSolid 参…

【环境搭建问题】linux服务器安装conda并创建虚拟环境

1.检查有没有conda 首先看root文件夹下有没有anaconda或者conda 没有的话就要先下载安装conda&#xff1a; https://repo.anaconda.com/archive/index.html 在这个链接下找自己需要的。服务器一般为linux&#xff0c;所以我这里选择的是&#xff1a; 2.安装conda 下载安装…

Electron学习笔记(二)Hello World

目录 前言 运行主进程 创建界面 使用窗口打开界面 管理窗口的生命周期 关闭所有窗口时退出应用 (Windows & Linux)​ 如果没有窗口打开则打开一个窗口 (macOS) 使用预加载脚本访问渲染器的Node.js 添加你自己的功能 完整代码展示 效果展示 前言 接上一篇文章 …

LINUX进程间的通信(IPC)--信号

一、概念 信号通信&#xff0c;其实就是内核向用户空间进程发送信号&#xff0c;只有内核才能发信号&#xff0c;用户空间进程不能发送信号。信号已经是存在内核中的了&#xff0c;不需要用户自己创建。 信号通信的框架 * 信号的发送&#xff08;发送信号进程&#xff09;&am…

JS图形引擎汇总

1、leaferjs leaferjs绚丽多彩的 HTML5 Canvas 2D 图形渲染引擎&#xff0c;可结合 AI 绘图、生成界面。 提供了丰富的 UI 绘图元素&#xff0c;和开箱即用的功能&#xff0c;如自动布局、图形编辑、SVG 导出&#xff0c;方便与 Figma、Sketch 等产品进行数据交换。并为跨平台…

示波器选择导出至USB闪存盘的三种格式(bmp、set、csv)

如下图所示&#xff0c;一般由示波器导出至U盘中&#xff0c;一共有三种文件格式。 1、当前屏幕图像(*.bmp) BMP 文件格式&#xff08;全称是位图文件格式&#xff0c;Bitmap Image File&#xff09;是一种图像文件格式&#xff0c;用于存储数字图像。它是一种无损图像格式&am…