当前位置: 首页 > news >正文

【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);
参数mutex:要初始化的互斥量,attr: NULL。
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】详解加锁实现线程互斥

一、多线程不加线程互斥可能会引发的问题 下面是一个抢标逻辑。抢票为什么会抢到负数&#xff1a;假设当票数为1时&#xff0c;此时四个进程的判断条件tickets都大于0&#xff0c;都会进入抢票操作&#xff0c;第一个进程抢完票以后tickets0并写回内存&#xff0c;第二个进程再…...

Java学习高级四

JDK8开始&#xff0c;接口新增了三种形式的方法 接口的多继承 内部类 成员内部类 静态内部类 局部内部类 匿名内部类 import javax.swing.*; import java.awt.event.ActionEvent;public class Test {public static void main(String[] args) {// 扩展 内部类在开发中的真实使用…...

mmc-utils 的 MMC 测试工具

MMC 工具介绍 有一个名为 mmc-utils 的 MMC 测试工具&#xff0c;由 Ulf Hansson 维护&#xff0c;您可以在以下公共 git 存储库中找到它&#xff1a; mmc/mmc-utils.git - Unnamed repository; edit this file description to name the repository. 功能 mmc-utils 工具可以…...

使用Python Turtle绘制圣诞树和装饰

简介(❤ ω ❤) 在这篇文章中&#xff0c;我们将探索如何使用Python的Turtle模块来绘制一个充满节日气氛的圣诞树&#xff0c;以及一些可爱的装饰品。Turtle是一个受Logo语言启发的图形库&#xff0c;非常适合初学者学习编程和创建图形。 码农不是吗喽&#xff08;大学生版&…...

非常好的新版网盘系统,是一款PHP网盘与外链分享程序,支持文件预览

这是一款PHP网盘与外链分享程序&#xff0c;支持所有格式文件的上传&#xff0c; 可以生成文件外链、图片外链、音乐视频外链&#xff0c;生成外链同时自动生成相应的UBB代码和HTML代码&#xff0c; 还可支持文本、图片、音乐、视频在线预览&#xff0c;这不仅仅是一个网盘&a…...

针对【module_or_function】的单元测试,全面覆盖可能的【edge_cases】

针对【module_or_function】的单元测试&#xff0c;全面覆盖可能的【edge_cases】 编写单元测试是为了验证代码模块或函数的正确性和鲁棒性。对于module_or_function&#xff0c;首先需要确定这个模块或函数的具体功能和预期输入范围。一个好的单元测试应该包括以下几个步骤&a…...

OTA测试!

OTA测试&#xff0c;全称“Over-The-Air Testing”&#xff0c;是一种无线通信设备的性能测试方法&#xff0c;主要用于评估设备在无线传输环境中的性能表现。以下是关于OTA测试的详细介绍&#xff1a; 一、定义与目的 OTA测试着重进行整机辐射性能方面的测试&#xff0c;以评…...

[H最短路] lc2959. 关闭分部的可行集合数目(Floyd最短路+二进制枚举+模板题)

文章目录 1. 题目来源2. 题目解析 1. 题目来源 链接&#xff1a;2959. 关闭分部的可行集合数目 2. 题目解析 看了看题好像还没啥思路&#xff0c;结果一看数据范围&#xff0c;好家伙…n 最大就 10 啊&#xff0c;那不直接闭眼直接 Floyd枚举所有情况即可吗&#xff1f;&…...

pyinstaller用法详解3

本文使用创作助手。 大家好&#xff0c;时隔多日&#xff0c;我又更新了pyinstaller的用法详解&#xff01; 当然&#xff0c;这一次要比之前更详细&#xff0c;十分详细。 谢谢大家的支持&#xff0c;我们现在开始&#xff01; 一、快速开始使用pyinstaller 我之前的文章…...

养猫新手不会挑智能猫砂盆?2024最新挑选干货分享!

不得不说智能猫砂盆真的帮了我很大的忙&#xff0c;四年以来我陆陆续续养了很多的猫咪&#xff0c;但是因为需要上班&#xff0c;所以有时候也对铲屎的工作有些力不从心&#xff0c;后面听了朋友的建议&#xff0c;去入手了智能猫砂盆&#xff0c;不得不说买智能猫砂盆也非常的…...

上海理工大学24计算机考研考情分析!初复试分值比55:45,复试逆袭人数不算多!

上海理工大学&#xff08;University of Shanghai for Science and Technology&#xff09;&#xff0c;位于上海市&#xff0c;是一所以工学为主&#xff0c;工学、理学、经济学、管理学、文学、法学、艺术学等多学科协调发展的应用研究型大学&#xff1b;是上海市属重点建设大…...

Pandas库学习之DataFrame.drop()函数

Pandas库学习之DataFrame.drop()函数 一、简介 DataFrame.drop 是 Pandas 库中一个非常实用的函数&#xff0c;用于删除 DataFrame 中的行或列。通过指定列名或行索引&#xff0c;可以灵活地从数据集中移除不需要的数据。这对于数据清洗和预处理非常有用。 二、语法和参数 D…...

WHAT - 介绍一个不太一样的 UI 组件库 shadcn/ui

目录 一、介绍主要特点核心组件示例代码社区和支持总结 二、copy/paste1. 高度可定制性2. 避免依赖锁定3. 学习和理解4. 简化调试5. 项目需求变化 官方文档&#xff1a;https://ui.shadcn.com/docs 一、介绍 ShadCN (ShadCN/UI) 是一个现代的 React 组件库&#xff0c;旨在提…...

python--实验 11 模块

目录 知识点 模块基础 模块使用方式 自定义模块示例 模块的有条件执行 Python包结构 定义和导入包 常用第三方库及安装 实例代码 第三方库自动安装脚本 Python标准库介绍 PyInstaller 小结 实验 1.(基础题)制作文本进度条。 2.(基础题) 蒙特卡罗方法计算圆周率…...

Vue3+Vite+TS+Axios整合详细教程

1. Vite 简介 Vite是新一代的前端构建工具&#xff0c;在尤雨溪开发Vue3.0的时候诞生。类似于Webpack Webpack-dev-server。其主要利用浏览器ESM特性导入组织代码&#xff0c;在服务器端按需编译返回&#xff0c;完全跳过了打包这个概念&#xff0c;服务器随起随用。生产中利用…...

【深度学习入门篇 ⑨】循环神经网络实战

【&#x1f34a;易编橙&#xff1a;一个帮助编程小伙伴少走弯路的终身成长社群&#x1f34a;】 大家好&#xff0c;我是小森( &#xfe61;ˆoˆ&#xfe61; ) &#xff01; 易编橙终身成长社群创始团队嘉宾&#xff0c;橙似锦计划领衔成员、阿里云专家博主、腾讯云内容共创官…...

宝塔安装RabbitMq教程

需要放开15672端口&#xff0c;默认账号密码为guest/guest...

韦东山嵌入式linux系列-驱动进化之路:设备树的引入及简明教程

1 设备树的引入与作用 以 LED 驱动为例&#xff0c;如果你要更换LED所用的GPIO引脚&#xff0c;需要修改驱动程序源码、重新编译驱动、重新加载驱动。 在内核中&#xff0c;使用同一个芯片的板子&#xff0c;它们所用的外设资源不一样&#xff0c;比如A板用 GPIO A&#xff0c…...

长轮询(Long Polling)实现原理和java代码示例

长轮询&#xff08;Long Polling&#xff09;背景 长轮询是一种在Web开发中常用的技术&#xff0c;用于实现服务器与客户端之间的即时通信或近乎实时的数据交换。在传统的轮询&#xff08;Polling&#xff09;中&#xff0c;客户端会定期向服务器发送请求以检查是否有新数据。…...

OWASP 移动应用 2024 十大安全风险

1. OWASP 移动应用 2024 十大安全风险 开放全球应用程序安全项目 &#xff08;OWASP&#xff09; 是一个非营利性基金会&#xff0c;致力于提高软件的安全性。自 2014、2016 年两次发布了移动应用的十大风险后&#xff0c;今年再次发布2024版。这对移动应用软件的检查工具有着…...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

在rocky linux 9.5上在线安装 docker

前面是指南&#xff0c;后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

工程地质软件市场:发展现状、趋势与策略建议

一、引言 在工程建设领域&#xff0c;准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具&#xff0c;正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

微信小程序云开发平台MySQL的连接方式

注&#xff1a;微信小程序云开发平台指的是腾讯云开发 先给结论&#xff1a;微信小程序云开发平台的MySQL&#xff0c;无法通过获取数据库连接信息的方式进行连接&#xff0c;连接只能通过云开发的SDK连接&#xff0c;具体要参考官方文档&#xff1a; 为什么&#xff1f; 因为…...

Redis数据倾斜问题解决

Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中&#xff0c;部分节点存储的数据量或访问量远高于其他节点&#xff0c;导致这些节点负载过高&#xff0c;影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek

文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama&#xff08;有网络的电脑&#xff09;2.2.3 安装Ollama&#xff08;无网络的电脑&#xff09;2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)

前言&#xff1a; 在Java编程中&#xff0c;类的生命周期是指类从被加载到内存中开始&#xff0c;到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期&#xff0c;让读者对此有深刻印象。 目录 ​…...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中&#xff0c;明确沟通敏捷转型目的尤为关键&#xff0c;团队成员只有清晰理解转型背后的原因和利益&#xff0c;才能降低对变化的…...