线程互斥及基于线程锁的抢票程序

我们实现一个简单的多线程抢票程序。 

#include<iostream>
#include<thread>
#include<unistd.h>
#include<functional>
#include<vector>
using namespace std;
template<class T>
using func_t=function<void(T)>;//返回值为void,参数为T
template<class T>
class Thread
{public:Thread(func_t<T> func,const string&name,T data):_tid(0),_func(func),_threadname(name),isrunning(false),_data(data){}static void*ThreadRoutine(void*args){//(void)args;//仅仅是为了防止编译器有告警Thread*ts=static_cast<Thread*>(args);ts->_func(ts->_data);return nullptr;}bool Start(){int n=pthread_create(&_tid,nullptr,ThreadRoutine,this);if(n==0){isrunning=true;return true;}return false;}bool Join(){if(!isrunning) return true;int n=pthread_join(_tid,nullptr);if(n==0){isrunning=false;return true;}return false;}string GetThreadName(){return _threadname;}bool IsRunning(){return isrunning;}~Thread(){}private:pthread_t _tid;string _threadname;bool isrunning;func_t<T> _func;T _data;
};
#include"test.hpp"
using namespace std;
string GetThreadName()
{static int number=1;char name[64];snprintf(name,sizeof name,"Thread - %d",number++);return name;
}
void print(int num)
{while(num--){cout<<"hello world"<<num<<endl;sleep(1);}
}
int ticket=100;
void GetTicket(string name)
{while(true){if(ticket>0){usleep(1000);printf("%s get a ticket %d\n",name.c_str(),ticket--);}elsebreak;}}
int main()
{int num=5;//vector<Thread<int>> Threads;string name1=GetThreadName();string name2=GetThreadName();string name3=GetThreadName();string name4=GetThreadName();Thread<string> t1(GetTicket,name1,name1);Thread<string> t2(GetTicket,name2,name2);Thread<string> t3(GetTicket,name3,name3);Thread<string> t4(GetTicket,name4,name4);t1.Start();t2.Start();t3.Start();t4.Start();t1.Join();t2.Join();t3.Join();t4.Join();// while(num--)// {//     Threads.push_back(Thread<int>(print,GetThreadName(),10));// }// for(auto &t:Threads)// {//     cout<<t.GetThreadName()<<" is running? "<<t.IsRunning()<<endl;// }// for(auto&t:Threads)// {//     t.Start();// }// for(auto &t:Threads)// {//     cout<<t.GetThreadName()<<" is running? "<<t.IsRunning()<<endl;// }// for(auto &t:Threads)// {//     t.Join();// }// Thread t(print,GetThreadName());// cout<<"Is thread running?"<<t.IsRunning()<<endl;// t.Start();// cout<<"Is thread running?"<<t.IsRunning()<<endl;// t.Join();return 0;
}

神奇的事情发生了,我们明明添加了ticket大于0时才能抢票的限制条件,

为什么最后ticket会小于0呢? 

判断ticket是否大于0也是访问公共资源,并不是原子的。

可能多个线程同时通过判断,但是在执行ticket--的时候又因时间片变成串行。

最终导致ticket小于0。

数据在内存中,本质是被线程共享的。

数据被读取到寄存器中,本质变成了线程的上下文,属于线程的私有数据。

我们把任何一个时刻,只允许一个线程访问的共享资源叫做临界资源。

进程中访问临界资源的代码就叫做临界区。

任何时刻,互斥保证只有一个执行流进入临界区,访问临界资源,通常对临界资源起保护作用。

原子性:不会被任何调度打断的操作,只有两态,完成或未完成。

我们认为,一条汇编语句就是原子的。

而像a++这样的C语言指令,实际上会被转化成三条汇编指令。

首先把a从内存拷贝到CPU的寄存器,字CPU中完成++操作,再返回内存,不是原子的。

为了不让上面的情况发生,需要加锁。 

 

 如图,加锁后,问题解决,不过速度变慢了。

申请锁本身是原子的,有宝马。这块的原理下一篇博客会介绍。

根据互斥的定义,任何一个时刻只允许一个线程申请锁成功,申请失败的进程在mutex阻塞,本质就是等待。

可能大家会认为,当线程进入锁,执行锁内代码,这是如果发生切换,还是会产生同样的错误。

其实这次不一样了,因为就算时间片到了,发生线程切换,被切换到的线程也没办法访问锁。

它在申请锁那里阻塞着呢。。。

这就保证了临界区的原子性。

就相当于上的线程的密码锁,专属的。

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

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

相关文章

XUbuntu18.04 源码编译Qt4.5.3的过程

由于新公司很多旧的软件都是基于这个版本做的嵌入式开发。 所以想要自己搭一套基于Linux的非嵌入式开发环境&#xff0c;方便用来调试和编译代码。 这样就可以完成在linux下开发&#xff0c;然后直接嵌入式打包&#xff0c;涉及到界面的部分就不需要上机调试看问题了。 所以…

Axure引用ECharts图表 解决火狐浏览器出错

Axure原型添加Echarts图表&#xff0c;没耐心看文章的可以直接下载示例 Axure中使用ECharts图表示例 1. 打开Axure新建页面 2. 页面添加元件 元件类型随意&#xff0c;矩形、动态面板、热区、图片 甚至段落都可以3. 命名元件 随意命名&#xff0c;单个页面用到多个图表时名…

机器学习-11-基于多模态特征融合的图像文本检索

总结 本系列是机器学习课程的系列课程&#xff0c;主要介绍机器学习中图像文本检索技术。此技术把自然语言处理和图像处理进行了融合。 参考 2024年&#xff08;第12届&#xff09;“泰迪杯”数据挖掘挑战赛 图像特征提取&#xff08;VGG和Resnet特征提取卷积过程详解&…

Facebook账号运营要用什么IP?

众所周知&#xff0c;Facebook封号大多数情况都是因为IP的原因。Facebook对于用户账号有严格的IP要求和限制&#xff0c;以维护平台的稳定性和安全性。在这种背景下&#xff0c;海外IP代理成为了一种有效的解决方案&#xff0c;帮助用户避免检测&#xff0c;更加快捷安全地进行…

学习笔记:Vue2中级篇

Vue2 学习笔记&#xff1a;Vue2基础篇_ljtxy.love的博客-CSDN博客学习笔记&#xff1a;Vue2中级篇_ljtxy.love的博客-CSDN博客学习笔记&#xff1a;Vue2高级篇_ljtxy.love的博客-CSDN博客 Vue3 学习笔记&#xff1a;Vue3_ljtxy.love的博客&#xff09;-CSDN博客 文章目录 5.…

SpringCloud系列(5)--SpringCloud微服务工程公共部分提取

前言&#xff1a;在上一章节中我们创建了两个个SpringCloud工程&#xff0c;但在两个工程中分别存在着一些重复的部分&#xff0c;例如重复的实体类&#xff08;如图所示&#xff09;&#xff0c;这样会造成系统的冗余&#xff0c;所以我们需要把公共的类提取到一个工程里&…

JavaScript变量及数据类型

目录 概述&#xff1a; 变量&#xff1a; 前言&#xff1a; 变量的命名&#xff1a; 定义变量&#xff1a; 为变量赋值&#xff1a; 变量提升&#xff1a; let和const关键字&#xff1a; JS数据类型&#xff1a; 前言&#xff1a; typeof操作符&#xff1a; JS基本…

RK3588 Android13 鼠标风格自定义动态切换

前言 电视产品,客户提供了三套鼠标图标过来,要求替换系统中原有丑陋风格且要支持动态切换, 并且在 TvSetting 中要有菜单,客户说啥就是啥呗,开整。 效果图 test framework 部分修改文件清单 png 为鼠标风格资源图片,这里就不提供了,可自由找一个替换一下就行 framew…

渐进时间复杂度O(n)

基本操作数 算法的运行速度受计算机性能的影响&#xff0c;所以通常考虑算法效率的不是算法运行的实际用时&#xff0c;而是算法运行所需要进行的基本操作的数量。 像加减乘除、访问变量、给变量赋值等都可以看作基本操作。对基本操作的计数或是估测可以作为评判算法用时的指标…

Python turtle海龟绘制美国队长盾牌

使用Python中的turtle模块绘制美队盾牌 具体思路如下&#xff1a; 导入海龟库第1个圆&#xff1a;半径 200&#xff0c;红色填充第2个圆&#xff1a;半径 150&#xff0c;白色填充第3个圆&#xff1a;半径 100&#xff0c;红色填充第4个圆&#xff1a;半径 50&#xff0c;蓝色…

CSS基础常用属性之字体属性(如果想知道CSS的字体属性知识点,那么只看这一篇就足够了!)

前言&#xff1a;在我们学习CSS的时候&#xff0c;主要学习选择器和常用的属性&#xff0c;而这篇文章讲解的就是最基础的属性之一——文字属性。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客 废话不多说&#xff0c;让我们直…

【C++】C++11 包装器

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》《算法》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 目录 前言 function包装器 fu…

RHCE:网络服务综合项目

基础配置&#xff1a; 1.配置主机名&#xff0c;静态IP地址 2.开启防火墙并配置 3.部分开启SElinux并配置 4.服务器之间使用同ntp.aliyun.com进行时间同步 5.服务器之间实现SSH免密登录 业务需求&#xff1a; 1.Server-NFS-DNS主机配置NFS服务器&#xff0c;将博客网…

【Lattice FPGA 开发】Modelsim与Diamond联合仿真

本文讲解Modelsim与Diamond进行联合仿真步骤&#xff0c;以及对遇到问题的解决与说明。 文章目录 软件版本0. Diamond设置文件为仿真文件特别注意 1. Diamond设置仿真软件为Modelsim2. Modelsim编译Lattice的库文件2.1 新建文件夹存放库文件2.2 Modelsim中建立新的仿真库2.2.1…

千锤百炼之算法Scanner和System.out引起超时解决办法

题外话 觉得这个内容还是很关键的,过来写一下吧 本次内容有点抽象大家试着听一下 正题 做过算法题的人都知道,无论是在力扣还是牛客或者别的网站刷题,很多情况下都会遇到输入输出的情况,当我们用Scanner和System.out.print()就有可能产生超时问题 如下图 接下来会有一段代…

远程计算机或设备将不接受连接_解决方法

重启了下电脑遇到了无法联网的问题&#xff0c;解决方法如下&#xff1a; 打开“控制面板”&#xff1b; 打开Internet选项&#xff1b; 点击“连接”&#xff1b; 点击“局域网设置”&#xff1b; 设置选项为下图&#xff1a; 连接成功了&#xff1a; 原因&#xff1a; 打…

数字化到底具有何种魔力!成为跟上时代的必经之路?

数字化确实具有深远的魔力和吸引力&#xff0c;成为现代企业在跟上时代步伐、实现持续发展和创新的重要驱动力。相较于传统信息化&#xff0c;数字化转型能够为企业带来更为显著和全面的降本增效效应。 首先&#xff0c;数字化转型通过深度融合信息技术和管理标准化&#xff0c…

GPU版本torch使用教程

GPU版本torch使用教程 一、下载配置CUDA和CUDNN &#xff08;1&#xff09;进入cmd使用nvidia-smi.exe查看自己电脑支持的最新CUDA版本&#xff08;可以下载地低版本&#xff09;&#xff0c;如图&#xff1a; 也可以通过NVIDIA控制面板&#xff08;NVIDIA Control Panel&am…

HTML重要标签梳理学习

1、HTML文件的框架 使用VS Code编码时&#xff0c;输入!选中第一个&#xff01;就可以快速生成一个HTML文件框架。 2、标签 <hr> <!--下划线--> <br> <!--换行--> <strong>加粗</strong> &…

C++11——线程库的理解与使用

目录 前言 一、线程库的构造 1.默认构造 2.带参构造 3.拷贝构造与赋值拷贝&#xff08;不支持&#xff09; 4.移动构造 二、线程调用lambda函数 三、线程安全与锁 1.lambda中的线程与锁 2.函数指针中的线程与锁 3.trylock() 4.recursive_mutex 5.lock_gurad守卫锁…