03_并发锁实现

news/2025/10/10 11:39:59/文章来源:https://www.cnblogs.com/Xiaomostream/p/19132713

通过10个线程池模拟火车站抢票问题

一. 用程序模拟这个过程

10个线程池共享 count 这个资源, 回调函数对count进行++操作
设置回调函数对当前count++十万次,看最后是否是100万次

gcc -o lock lock.c -lpthread

最终由于不同线程抢占,导致最终 count 实际是 < 100万

二. 原因分析

count是一个临界资源(多个线程共享的一个资源)
count ++; 这一行代码其实对应三个指令

  1. mov [count], eax; //把count的值传给寄存器eax
  2. inc eax; //eax+1
  3. mov eax, count; //把寄存器eax的值赋值给count

(1)理想情况下,执行这三条指令时不会进行线程间的切换
(2)但是非正常情况下, 假设当前count = 50, 线程1执行完 1) mov [count], eax 指令后,发生线程的切换,
如果线程2 执行完 这三条指令后count = 51, 此时又切换为线程1执行后续的两条指令,由于寄存器eax,eax的值为50,
count 最后等于51,这就是count < 100万的原因

三. 解决方法

对临界资源count加锁或者使用原子操作

1) 互斥锁 mutex: 把这三条指令锁到一起执行,其他线程进不来,这个过程引起了线程的切换,但是进不来只能等待下一次被调用

使用场景:锁的内容比较多。比如,线程安全的rbtree, 添加可以用mutex
pthread_mutex_lock(&mutex);
(*pcount) ++;
pthread_mutex_unlock(&mutex);

2) 自旋锁 spinlock: 一旦锁上,相当于使用一个 while(1),等待该把锁被释放,不会进行线程切换

适用场景:锁的内容很少
具体使用哪把锁的核心是线程切换的代价(mutex)与线程等待的代价(spinlock)

3) 原子操作:把多条指令通过单条CPU指令实现(汇编指令实现):xaddl 1, [count]

由于使用单条CPU指令,根本不可能被分割指向。
asm volatile(
"lock; xaddl %2, %1;" //把 %2(add) 加给 %1(value)
: "=a" (old) //返回值给a
: "m" (
value), "a"(add)
: "cc", "memory"
);

4) CAS: Compare And Swap

CAS 是一种原子操作,核心思想是 "先比较,再交换",用于解决多线程对共享资源的并发修改问题。
通过比较内存中的值与期望值是否一致,如果一致则交换值。如果不一致,则操作失败并返回当前的值。

CAS操作接收三个参数:

  1. 内存地址(V):要进行比较和交换操作的目标内存位置(例如某个变量的地址)。
  2. 旧值(A):期望的当前值。CAS操作会检查内存中该位置的值是否与此旧值相等。
  3. 新值(B):如果内存中当前值与旧值一致,则将内存中的值更新为新值。

CAS的执行流程:
- 比较内存位置V的当前值是否等于期望值A。
- 如果相等,则将V的值替换为新值B。
- 如果不相等,则操作失败,V的值保持不变,返回当前值。

优点:
性能优越:CAS避免了传统锁的性能开销,特别是在低竞争环境下。
无阻塞:相比传统的锁机制,CAS能够避免线程阻塞,减少上下文切换的开销。
适用性广:CAS是实现各种原子操作的基础,适用于许多并发算法。
缺点:
高竞争时的性能问题:在高竞争环境下,CAS操作可能会频繁失败,导致大量重试,浪费CPU时间,称为自旋瓶颈。
ABA问题:如果一个值从A变为B再变回A,CAS操作无法检测到这种变化,导致潜在的错误。这通常可以通过版本号或标记位的技术解决。

Code

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>#define THREAD_COUNT 10pthread_mutex_t mutex; //定义一把互斥锁pthread_spinlock_t spinlock; //定义一把自旋锁int inc(int *value, int add) {//对value这个地址所指向的元素加上 addint old;__asm__ volatile("lock; xaddl %2, %1;": "=a" (old): "m" (*value), "a"(add): "cc", "memory");return old;
}int CAS(int *value, int expected, int new_val) {unsigned char ret;__asm__ volatile("lock; cmpxchgl %2, %1;"  // lock前缀保证多核下的原子性,cmpxchgl比较并交换"sete %0;"                // 若相等,result=1;否则result=0(sete:相等则置位): "=q"(ret), "+m"(*value)  // 输出:result是结果, *value是读写的内存地址: "r"(new_val), "a"(expected) // 输入:new_val是要写的新值,expected在EAX寄存器里: "cc", "memory"  // 通知编译器该操作影响条件码寄存器);return ret;
}
void CAS_inc(int *value) {int old, new_val;do {old = *value;new_val = old+1;} while(!CAS(value, old, new_val)); // 若CAS失败(值被修改),重试直到成功
}
void *thread_callback(void *arg) {int *pcount = (int *)arg;// 取出线程创建时传入的 countint i = 0;while(i ++ < 100000) {
#if 0(*pcount) ++;
#elif 0pthread_mutex_lock(&mutex);(*pcount) ++;pthread_mutex_unlock(&mutex);
#elif 0pthread_spin_lock(&spinlock);(*pcount) ++;pthread_spin_unlock(&spinlock);
#elif 0inc(pcount, 1);
#elseCAS_inc(pcount);
#endifusleep(1);}
}int main() {pthread_t threadid[THREAD_COUNT] = {0};pthread_mutex_init(&mutex, NULL);pthread_spin_init(&spinlock, PTHREAD_PROCESS_SHARED);int i = 0;int count = 0;  // 共享资源:总票数(初始0,最终应变为100万)for (i = 0; i < THREAD_COUNT; i ++) {//创建线程函数pthread_create(&threadid[i], NULL, thread_callback, &count);/*第一个参数 是这个线程返回的的id地址第二个参数 是线程的属性,比如堆、栈第三个参数 是线程的入口函数第四个参数 是往线程的入口函数传入的参数*/}for (i = 0; i < 100; i ++) {printf("count : %d\n", count);sleep(1);}return 0;
}

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

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

相关文章

爱人先爱己

我爱的人教会我被抛弃的时候不要做任何挣扎,教会了我真诚不是必杀技,教会了我对人不能太好,爱人不要爱满,自从那天后我花了很长一段时间找回我自己,我警惕一切我迷恋的东西,以防止失去的痛苦,对任何人都不报期待…

2025 空气离合器生产厂家最新推荐榜:电网冲击缓解技术测评与可靠性排行,含单片多片机型及核心部件企业

在矿山、冶金、水泥等重型工业领域,空气离合器作为磨矿机等大型设备的核心传动部件,其性能直接决定生产稳定性与成本控制效率。当前行业正面临三大核心痛点:大功率电动机启动时的巨大电流常引发电网波动甚至跳闸,“…

2025 气动离合器厂家最新推荐榜权威发布:聚焦博得 PLC 技术与新兴品牌降本优势多片式气动离合器/气动离合器电磁阀/气动离合器气缸/气动离合器摩擦片/单片式气动离合器厂家推荐

在矿山、冶金、水泥等重型工业领域,气动离合器作为磨矿机等大型设备的核心传动部件,其性能直接决定生产稳定性与成本控制效率。当前行业正面临多重亟待解决的痛点:大功率电机启动时的冲击电流易引发电网波动,“大马…

Unicode 编码解码工具类

/*** 字符串转 Unicode 编码(标准格式 \\uXXXX)*/public static String stringToUnicode(String str) {if (str == null || str.isEmpty()) {return "";}StringBuilder unicode = new StringBuilder();for…

2025 木粉源头厂家最新推荐榜:全品类适配 / 稳定供应 / 技术赋能品牌权威解析,采购必看杂/刨花/木塑/化工/造纸/香/猫砂木粉厂家推荐

木粉作为化工、木塑、造纸、宠物用品等多领域的核心原料,其品类适配性、质量稳定性直接影响终端产品竞争力。当前市场中,采购方常面临三大痛点:一是需求精细化与供应同质化的矛盾,专用粉性能不达标、基础粉纯度不足…

mergeGDS

描述:脚本: streamOut ../output/latest/${design_name}.gds.gz \-units 1000 \-structureName ${design_name} \-mapFile ../scr/streamOut.map \-merge $gds_files \-mode ALL逐条解释:

有奖话题:Data Agent for Meta 能否成为企业级 “数据大脑”?

随着生成式人工智能(Generative AI)从概念验证迈向规模化商业落地,AI Agent已成为企业核心业务流程的重要组成部分。然而,当模型调用日益便捷时,核心痛点已不再是模型本身,而是集中在一个关键要素上:数据。传统…

汉印打印机N41BT驱动 安装后无法打印

HPRTN41BT Windows驱动我使用的是汉印N41BT打印机, 电脑重装系统后,安装了N41BT 还是无法打印, 解决办法 一,先安装对应型号的打印驱动,比如我的是 汉印 型号:N41BT 驱动安装好后, 然进电脑设置 ,我的是win10…

新的练习项目

最近新发现了一个特别好的练习项目,进阶学习使用的,12306 plus版马丁大佬的,预备在十月内学完! 惊喜程度不亚于第一个hello world

最简单的 Web 打印方案:用 5 分钟上手 web-print-pdf(npm 包) - 实践

最简单的 Web 打印方案:用 5 分钟上手 web-print-pdf(npm 包) - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: …

2025 年塑木厂家最新推荐:实力厂家排行榜 —— 含围栏地板栈道等产品企业技术服务优势解析塑木地板/栈道/护栏/门板/凉亭/墙板/托盘厂家推荐

当前户外景观与公共设施建设中,塑木材料因环保耐用特性需求激增,但市场乱象凸显。多数消费者面临选品难题:部分厂家无核心技术,产品抗压、抗紫外线能力差,难适应不同地域气候;服务断层导致设计施工脱节,售后响应…

如何将GIS属性一键快速标注到AutoCAD图纸上?

假如有成百上千个地块、管线或设备需要标注名称和编号,手动逐个输入文本不仅耗时巨大,而且极易出错。借助GIS4CAD插件可以快速地将选定的GIS属性字段值(如地名、编号)作为文本快速标注到图纸实体上。此功能实现了“…

深入解析:设计模式(C++)详解——命令模式(2)

深入解析:设计模式(C++)详解——命令模式(2)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", &…

坯子插件库 v3.2.1 for SketchUp 2022-2024下载与安装教程

坯子插件库 v3.2.1 for SketchUp 2022-2024 是一款专为 SketchUp 2022 至 2024 版本设计的插件管理工具,集插件下载、安装、卸载及更新功能于一体,支持一键操作简化流程。该工具内置丰富插件资源库,涵盖建筑构件、线…

免费绿色版识别软件,OCR识别软件!最全安装使用教程(附下载地址)

软件介绍 这个OCR识别非常的小巧,支持离线,支持所有的Windows系统,非常适合老电脑或者不联网的电脑使用, 软件为绿色免安装,解压出来双击“识别”程序就启动了(没有反应的就鼠标右键用管理员身份运行)。 之前也…

实用指南:云原生网络基础设施的核心组件Envoy

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

zookeeper常用操作 - 吾辈当奋斗

cd /home/zookeeper/bin# 登录客户端sh zkCli.sh# 查看有几个服务注册到此ls /services # 查看下面的实例,具体的IP+端口ls /services/lulu

基于旋转不变子空间(ESPRIT)算法的DOA估计

一、ESPRIT算法核心原理 1.1 旋转不变性基础 ESPRIT通过阵列的几何对称性构建旋转不变性,利用两个子阵列接收信号的相位差直接估计DOA。对于均匀线阵(ULA),相邻阵元间距为d,信号入射角θ的相位延迟为:两个子阵列…

zedboard + AD-FMCOMMS3-EBZ HDL VIVADO 工程构建(二) 构建HDL项目

zedboard + AD-FMCOMMS3-EBZ HDL VIVADO 工程构建(二) 构建HDL项目 Build an HDL project — HDL documentation构建工程,需要 Linux 环境, windows 11 下 使用 WSL2