【Linux】详解加锁实现线程互斥
一、多线程不加线程互斥可能会引发的问题
下面是一个抢标逻辑。抢票为什么会抢到负数:假设当票数为1时,此时四个进程的判断条件tickets都大于0,都会进入抢票操作,第一个进程抢完票以后tickets==0并写回内存,第二个进程再从内存中读取tickets的值时此时tickets已经为0,再做--就变成了-1,tickets为负数就是这么来的。也就是说,多线程代码如果不对共享资源做保护可能会有并发问题。
二、互斥锁
2.1、静态分配锁
如果你定义的锁是静态的或者是全局的,可以直接初始化成
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
2.2、动态分配锁销毁锁
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex) ;
注意: 使用 PTHREAD_ MUTEX_ INITIALIZER 初始化的互斥量不需要销毁。
2.3、加锁解锁
int pthread_mutex_lock(pthread_mutex_t *mutex);int pthread_mutex_unlock(pthread_mutex_t *mutex);
返回值:成功返回0,失败返回错误号 。 pthread_mutex_lock函数如果申请锁成功就会继续向后运行,如果申请失败该函数就会阻塞不允许继续向后运行。
加锁的粒度要越细越好。
三、加锁的底层理解
movb $0,%al表示将0存入%al寄存器中(%al是累加寄存器AX的低8位部分,可以独立作为8位寄存器使用。), xchgb %al, mutex表示交换%al寄存器中的值和内存mutex中的值,如果内存mutex中的值原本是1,交换完则表示得到锁,否则挂起等待。unlock中将1存入mutex内存中表示归还锁。这样无论如何,得到1的线程始终只会有一个,也就做到了线程互斥。
四、多线程实现简单的互斥抢票
//thread.hpp
#ifndef __THREAD_HPP__
#define __THREAD_HPP__#include <iostream>
#include <string>
#include <unistd.h>
#include <functional>
#include <pthread.h>namespace ThreadModule
{template<typename T>using func_t = std::function<void(T)>;// typedef std::function<void(const T&)> func_t;template<typename T>class Thread{public:void Excute(){_func(_data);}public:Thread(func_t<T> func, T data, const std::string &name="none-name"): _func(func), _data(data), _threadname(name), _stop(true){}//记住此方法static void *threadroutine(void *args) // 类成员函数,形参是有this指针的!!{Thread<T> *self = static_cast<Thread<T> *>(args);self->Excute();return nullptr;}bool Start(){int n = pthread_create(&_tid, nullptr, threadroutine, this);if(!n){_stop = false;return true;}else{return false;}}void Detach(){if(!_stop){pthread_detach(_tid);}}void Join(){if(!_stop){pthread_join(_tid, nullptr);}}std::string name(){return _threadname;}void Stop(){_stop = true;}~Thread() {}private:pthread_t _tid;std::string _threadname;T _data;func_t<T> _func;bool _stop;};
} #endif
//LockGuard.hpp
#ifndef __LOCK_GUARD_HPP__
#define __LOCK_GUARD_HPP__#include <iostream>
#include <pthread.h>class LockGuard
{
private:pthread_mutex_t* _mutex;
public:LockGuard( pthread_mutex_t* mutex):_mutex(mutex){pthread_mutex_lock(_mutex);}~LockGuard(){pthread_mutex_unlock(_mutex);}};#endif
//testThread.cc
#include <iostream>
#include <vector>
#include "LockGuard.hpp"
#include "Thread.hpp"
using namespace ThreadModule;int g_tickets = 10000;
const int num = 4;class ThreadData
{
public:int &_tickets; // 所有的线程,最后都会引用同一个全局的g_ticketsstd::string _name;int _total;pthread_mutex_t &_mutex;public:ThreadData(int &tickets, const std::string &name, pthread_mutex_t &mutex): _tickets(tickets), _name(name), _total(0), _mutex(mutex){}~ThreadData(){}
};void route(ThreadData *td)
{while (true){LockGuard guard(&td->_mutex);if (td->_tickets > 0){usleep(1000);printf("%s running, get tickets: %d\n", td->_name.c_str(), td->_tickets); td->_tickets--; td->_total++;}elsebreak;}
}int main()
{pthread_mutex_t mutex;pthread_mutex_init(&mutex,nullptr);std::vector<Thread<ThreadData*>> threads;std::vector<ThreadData *> datas;//1、创建一批线程for(int i = 0; i<num; i++){std::string name = "thread-" + std::to_string(i+1);ThreadData* td = new ThreadData(g_tickets, name, mutex);threads.emplace_back(route, td, name);datas.emplace_back(td);}// 2. 启动 一批线程for (auto &thread : threads){thread.Start();}// 3. 等待一批线程for (auto &thread : threads){thread.Join();}sleep(1);// 4. 输出统计数据for (auto data : datas){std::cout << data->_name << " : " << data->_total << std::endl;delete data;}pthread_mutex_destroy(&mutex);return 0;
}
相关文章:
【Linux】详解加锁实现线程互斥
一、多线程不加线程互斥可能会引发的问题 下面是一个抢标逻辑。抢票为什么会抢到负数:假设当票数为1时,此时四个进程的判断条件tickets都大于0,都会进入抢票操作,第一个进程抢完票以后tickets0并写回内存,第二个进程再…...
Java学习高级四
JDK8开始,接口新增了三种形式的方法 接口的多继承 内部类 成员内部类 静态内部类 局部内部类 匿名内部类 import javax.swing.*; import java.awt.event.ActionEvent;public class Test {public static void main(String[] args) {// 扩展 内部类在开发中的真实使用…...
mmc-utils 的 MMC 测试工具
MMC 工具介绍 有一个名为 mmc-utils 的 MMC 测试工具,由 Ulf Hansson 维护,您可以在以下公共 git 存储库中找到它: mmc/mmc-utils.git - Unnamed repository; edit this file description to name the repository. 功能 mmc-utils 工具可以…...
使用Python Turtle绘制圣诞树和装饰
简介(❤ ω ❤) 在这篇文章中,我们将探索如何使用Python的Turtle模块来绘制一个充满节日气氛的圣诞树,以及一些可爱的装饰品。Turtle是一个受Logo语言启发的图形库,非常适合初学者学习编程和创建图形。 码农不是吗喽(大学生版&…...
非常好的新版网盘系统,是一款PHP网盘与外链分享程序,支持文件预览
这是一款PHP网盘与外链分享程序,支持所有格式文件的上传, 可以生成文件外链、图片外链、音乐视频外链,生成外链同时自动生成相应的UBB代码和HTML代码, 还可支持文本、图片、音乐、视频在线预览,这不仅仅是一个网盘&a…...
针对【module_or_function】的单元测试,全面覆盖可能的【edge_cases】
针对【module_or_function】的单元测试,全面覆盖可能的【edge_cases】 编写单元测试是为了验证代码模块或函数的正确性和鲁棒性。对于module_or_function,首先需要确定这个模块或函数的具体功能和预期输入范围。一个好的单元测试应该包括以下几个步骤&a…...
OTA测试!
OTA测试,全称“Over-The-Air Testing”,是一种无线通信设备的性能测试方法,主要用于评估设备在无线传输环境中的性能表现。以下是关于OTA测试的详细介绍: 一、定义与目的 OTA测试着重进行整机辐射性能方面的测试,以评…...
[H最短路] lc2959. 关闭分部的可行集合数目(Floyd最短路+二进制枚举+模板题)
文章目录 1. 题目来源2. 题目解析 1. 题目来源 链接:2959. 关闭分部的可行集合数目 2. 题目解析 看了看题好像还没啥思路,结果一看数据范围,好家伙…n 最大就 10 啊,那不直接闭眼直接 Floyd枚举所有情况即可吗?&…...
pyinstaller用法详解3
本文使用创作助手。 大家好,时隔多日,我又更新了pyinstaller的用法详解! 当然,这一次要比之前更详细,十分详细。 谢谢大家的支持,我们现在开始! 一、快速开始使用pyinstaller 我之前的文章…...
养猫新手不会挑智能猫砂盆?2024最新挑选干货分享!
不得不说智能猫砂盆真的帮了我很大的忙,四年以来我陆陆续续养了很多的猫咪,但是因为需要上班,所以有时候也对铲屎的工作有些力不从心,后面听了朋友的建议,去入手了智能猫砂盆,不得不说买智能猫砂盆也非常的…...
上海理工大学24计算机考研考情分析!初复试分值比55:45,复试逆袭人数不算多!
上海理工大学(University of Shanghai for Science and Technology),位于上海市,是一所以工学为主,工学、理学、经济学、管理学、文学、法学、艺术学等多学科协调发展的应用研究型大学;是上海市属重点建设大…...
Pandas库学习之DataFrame.drop()函数
Pandas库学习之DataFrame.drop()函数 一、简介 DataFrame.drop 是 Pandas 库中一个非常实用的函数,用于删除 DataFrame 中的行或列。通过指定列名或行索引,可以灵活地从数据集中移除不需要的数据。这对于数据清洗和预处理非常有用。 二、语法和参数 D…...
WHAT - 介绍一个不太一样的 UI 组件库 shadcn/ui
目录 一、介绍主要特点核心组件示例代码社区和支持总结 二、copy/paste1. 高度可定制性2. 避免依赖锁定3. 学习和理解4. 简化调试5. 项目需求变化 官方文档:https://ui.shadcn.com/docs 一、介绍 ShadCN (ShadCN/UI) 是一个现代的 React 组件库,旨在提…...
python--实验 11 模块
目录 知识点 模块基础 模块使用方式 自定义模块示例 模块的有条件执行 Python包结构 定义和导入包 常用第三方库及安装 实例代码 第三方库自动安装脚本 Python标准库介绍 PyInstaller 小结 实验 1.(基础题)制作文本进度条。 2.(基础题) 蒙特卡罗方法计算圆周率…...
Vue3+Vite+TS+Axios整合详细教程
1. Vite 简介 Vite是新一代的前端构建工具,在尤雨溪开发Vue3.0的时候诞生。类似于Webpack Webpack-dev-server。其主要利用浏览器ESM特性导入组织代码,在服务器端按需编译返回,完全跳过了打包这个概念,服务器随起随用。生产中利用…...
【深度学习入门篇 ⑨】循环神经网络实战
【🍊易编橙:一个帮助编程小伙伴少走弯路的终身成长社群🍊】 大家好,我是小森( ﹡ˆoˆ﹡ ) ! 易编橙终身成长社群创始团队嘉宾,橙似锦计划领衔成员、阿里云专家博主、腾讯云内容共创官…...
宝塔安装RabbitMq教程
需要放开15672端口,默认账号密码为guest/guest...
韦东山嵌入式linux系列-驱动进化之路:设备树的引入及简明教程
1 设备树的引入与作用 以 LED 驱动为例,如果你要更换LED所用的GPIO引脚,需要修改驱动程序源码、重新编译驱动、重新加载驱动。 在内核中,使用同一个芯片的板子,它们所用的外设资源不一样,比如A板用 GPIO A,…...
长轮询(Long Polling)实现原理和java代码示例
长轮询(Long Polling)背景 长轮询是一种在Web开发中常用的技术,用于实现服务器与客户端之间的即时通信或近乎实时的数据交换。在传统的轮询(Polling)中,客户端会定期向服务器发送请求以检查是否有新数据。…...
OWASP 移动应用 2024 十大安全风险
1. OWASP 移动应用 2024 十大安全风险 开放全球应用程序安全项目 (OWASP) 是一个非营利性基金会,致力于提高软件的安全性。自 2014、2016 年两次发布了移动应用的十大风险后,今年再次发布2024版。这对移动应用软件的检查工具有着…...
Qt界面假死原因
创建一个播放器类,继承QLabel,在播放器类中起一个线程用ffmpeg取流解码,将解码后的图像保存到队列,在gui线程中调用update()刷新显示。 当ffmpeg打开视频流失败后调用update()将qlabel刷新为黑色,有一定概率会使得qla…...
python调用MATLAB出错matlab.engine.MatlabExecutionError无法调用MATLAB函数报错
python调用MATLAB出错matlab.engine.MatlabExecutionError无法调用MATLAB函数报错 说明(废话)解决方案MATLAB异常乱码python矩阵转MATLAB矩阵matlab.engine.MatlabExecutionError 说明(废话) python调用MATLAB,调用m文件中的函数,刚开始都没有问题&…...
[GXYCTF2019]Ping Ping Ping1
打开靶机 结合题目名称,考虑是命令注入,试试ls 结果应该就在flag.php。尝试构造命令注入载荷。 cat flag.php 可以看到过滤了空格,用 $IFS$1替换空格 还过滤了flag,我们用字符拼接的方式看能否绕过,ag;cat$IFS$1fla$a.php。注意这里用分号间隔…...
成为git砖家(1): author 和 committer 的区别
大家好,我是白鱼。一直对 git author 和 committer 不太了解, 今天通过 cherry-pick 的例子搞清楚了区别。 原理 例如我克隆了著名开源项目 spdlog 的源码, 根据某个历史 commit A 创建了分支, 然后 cherry-pick 了这个 commit …...
Lianwei 安全周报|2024.07.15
新的一周又开始了,以下是本周「Lianwei周报」,我们总结推荐了本周的政策/标准/指南最新动态、热点资讯和安全事件,保证大家不错过本周的每一个重点! 政策/标准/指南最新动态 01 《人工智能全球治理上海宣言》发布 我们强调共同促…...
Linux - 基础开发工具(yum、vim、gcc、g++、make/Makefile、git、gdb)
目录 Linux软件包管理器 - yum Linux下安装软件的方式 认识yum 查找软件包 安装软件 如何实现本地机器和云服务器之间的文件互传 卸载软件 Linux编辑器 - vim vim的基本概念 vim下各模式的切换 vim命令模式各命令汇总 vim底行模式各命令汇总 vim的简单配置 Linux编译器 - gc…...
Git使用介绍教程
Git使用介绍教程 小白第一次写博客,内容写的可能不是很详细,仅供参考,大家一起努力 gitee网址:https://gitee.com 大部分的开发团队都以 Git 作为自己的版本控制工具,需要对 Git 的使用非常的熟悉。这篇文章中本人整理了自己在开发过程中经常使用到的 Git 命令,方便在偶…...
STM32的TIM1之PWM互补输出_死区时间和刹车配置
STM32的TIM1之PWM互补输出_死区时间和刹车配置 1、定时器1的PWM输出通道 STM32高级定时器TIM1在用作PWM互补输出时,共有4个输出通道,其中有3个是互补输出通道,如下: 通道1:TIM1_CH1对应PA8引脚,TIM1_CH1N对应PB13引…...
C++复习的长文指南
C复习的长文指南 一、入门语法知识1.预备1.1 main函数1.2 注释1.3 变量1.3 常量1.4 关键字1.5 标识符明明规则 2. 数据类型2.1 整型2.1.1 sizeof关键字 2.2 实型(浮点型)2.3 字符型2.4 转义字符2.5 字符串型2.6 布尔类型bool2.7 数据的输入 3. 运算符3.1…...
深入了解MySQL文件排序
数据准备 CREATE TABLE user_info (id bigint(20) NOT NULL AUTO_INCREMENT COMMENT ID,name varchar(20) NOT NULL COMMENT 用户名,age tinyint(4) NOT NULL DEFAULT 0 COMMENT 年龄,sex tinyint(2) NOT NULL DEFAULT 0 COMMENT 状态 0:男 1: 女,creat…...
柯林建站程序/信息流优化师招聘
蓝鸥iOS讲师推荐:事实上NSNumber的父类是NSValue,在OC中如何理解NSNumber的数字对象,下面就来简单的说一下!在日常编程中也许会遇到需要将基本数据类型转换成对象,如:基本类型放入到集合中(coco…...
做微信视频的网站/加盟
hello,大家好,今天豆皮范儿给大家带来了贝塞尔曲线推导和应用,优美的贝塞尔曲线想起了大学时候老师在给我们讲如何实现,如何推导,如何实现和应用。本来也来详细介绍一下,纯纯的干货~作者&#x…...
石家庄企业网站建设价格/英文网站建设
由于使用的是云主机,用键盘操作的话,只能打开本地的,所以底下的操作只用鼠标点击打开windows2012r2“桌面图标设置”窗口的命令如下rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,0当然要是本地的话,直接 “windows键” “r…...
官网的网站建设公司/推广公司
在某台机器上(跑着apache)为某个域名(如www.selboo.com.cn)做反向代理正好知道apache有mod_proxy这个 东东于是看了看文档写下了如下的配置文件: <VirtualHost *:80>ServerName www.selboo.com.cnProxyPass / http://www.selboo.com.cn/ProxyPassReverse / ht…...
网站个人博客怎么做/百度图片搜索引擎
Linux下推荐的常用应用程序列表一,网页浏览1,firefoxfirefox是现在最火的一个浏览器,支持好多扩展和插 件,也有很多漂亮的主题.firefox就是mozilla-firefox,他是把mozilla的网页浏览的功能分离为一个单独的浏览 器.Firefox一般是linux系统自带的默认浏览器.2,opera(非开源免费软…...
flickr wordpress/社群营销的具体方法
IP Messenger是一款局域网内部聊天、文件传输工具,具有很多优点,如数据通讯不需要建立服务器、直接在两台电脑间通信和数据传输,支持文件及文件目录的传输,安全快捷以及小巧方便等优异特点,因此很多公司都采用它作为部…...