Linux--为什么多线程共享全局变量结果错乱?无锁并发的数据竞争深度剖析

发布时间:2026/11/14 21:28:00

Linux--为什么多线程共享全局变量结果错乱?无锁并发的数据竞争深度剖析 为什么多线程共享全局变量结果错乱并发数据竞争深度剖析前言初学多线程时最经典的坑明明设定100张票多窗口并发售卖最后不仅卖出重复票总售票数还远超100张变量数值完全不符合预期。这就是数据竞争竞态条件根源是多线程无保护并发操作临界资源。本文从基础概念、代码复现、底层汇编原理层层拆解错乱原因理清原子操作与线程调度逻辑最后引出解决方案完整串起互斥锁诞生的背景。一、四个核心基础概念通俗释义1. 临界资源多个线程都能读写、共享使用的资源同一时间只允许一个线程操作全局变量、全局数组、打开的文件、共享内存都属于临界资源。售票案例中全局变量 ticket 就是典型临界资源。2. 临界区线程代码里专门用来访问、修改临界资源的代码片段也就是操作共享变量的那几行代码。本例中 if(ticket0) 判断、打印票数、ticket-- 扣减票数整段逻辑都属于临界区。3. 互斥约束规则任意时刻临界区内最多只能有一个线程进入执行一个线程在临界区操作时其余线程全部在外等待以此保护临界资源数据不乱改。4. 原子性操作不可拆分、不可被CPU调度打断只有两种最终状态完整全部执行完毕或是完全没开始执行不存在执行一半暂停的情况。简单举例喝水是原子操作拿起水杯、仰头、放下拆成三步就不是原子操作。二、问题复现无锁多线程售票代码完整源码#includestdio.h#includestdlib.h#includeunistd.h#includepthread.h// 临界资源全局共享票数intticket100;void*route(void*arg){constchar*id(constchar*)arg;while(1){if(ticket0){usleep(1000);// 模拟真实售票业务耗时printf([%s] 售出票%d\n,id,ticket);ticket--;// 核心问题代码}else{break;}}returnNULL;}intmain(void){pthread_tt[4];constchar*ids[]{窗口1,窗口2,窗口3,窗口4};for(inti0;i4;i){pthread_create(t[i],NULL,route,(void*)ids[i]);}for(inti0;i4;i){pthread_join(t[i],NULL);}return0;}编译运行指令gcc test.c-oticket-lpthread./ticket异常现象重复售卖同一张票多个窗口打印相同票号票数最终出现负数总售票数量超过初始100张发生严重超卖每次运行打印顺序、最终票数结果都不一样结果随机难以复现。三、逐层拆解数据错乱两大核心原因原因1ticket-- 并非原子操作底层拆分为三条独立汇编指令C语言看似一行自减代码CPU执行时会拆成三步每一步都可能被线程调度打断Load加载把内存中的 ticket 值读取到CPU寄存器Update运算寄存器内数值减1Store写回将运算后的数值重新写回内存覆盖原值。举极端场景初始 ticket100线程1读取100存入寄存器刚完成加载操作系统切换CPU挂起线程1线程2同样读取内存中100完成三步自减内存票数变为99CPU切回线程1线程1继续执行寄存器里100减1写回内存票数再次变成99两次售票操作票数只减少1直接造成漏扣票数、后续超卖。原因2线程抢占式调度判断与业务延时存在空隙代码里 usleep(1000) 模拟售票等待线程判断 ticket0 进入代码段后进入休眠。此时CPU空闲操作系统会调度其余线程运行多个线程先后判断票数有效全部进入临界区排队等待扣票休眠结束后统一执行 ticket-- 同一票号被多个线程卖出。简单比喻电影院只剩最后一张票四个售票员同时查到有票都收下顾客钱等出票时才发现票早已被别人卖掉出现重复出票。四、竞态条件总结多个线程并发进入临界区执行非原子操作程序最终运行结果依赖操作系统线程调度的先后顺序这种不确定的竞争现象就叫做竞态条件Race Condition也就是我们所说的数据竞争。局部变量存放在线程私有栈空间仅当前线程可访问不存在竞争只有全局变量、堆内存共享数据这类跨线程可见资源才会触发数据竞争。五、数据竞争的解决思路引出互斥量想要彻底杜绝票数错乱必须满足三条约束同一时刻临界区代码只允许一个线程进入执行临界区空闲时等待的线程可正常进入不会无限阻塞线程离开临界区后及时放行等待线程互不干扰。Linux系统提供 **互斥量mutex互斥锁**实现以上规则线程进入临界区前加锁离开临界区后解锁持有锁的线程独占临界资源其余线程加锁时阻塞等待从根源隔绝多线程同时修改共享变量消灭数据竞争。文末小结数据竞争本质共享临界资源 非原子操作 线程抢占调度单行C代码未必是原子操作算术自增、判断赋值都可能拆分多条指令全局变量天然存在线程竞争风险访问时必须划定临界区通过锁机制实现互斥保护本篇为互斥锁前置理论篇下一篇将详解pthread_mutex互斥量完整使用规范与编码避坑。
延伸阅读

更多相关文章

2026/11/14 21:19:38

RTP技术人周末指南:自动化活动发现与高效社区参与

最近在整理本地技术社区活动时,发现很多开发者朋友,尤其是刚搬到罗利/达勒姆(Raleigh/Durham)三角研究园(RTP)区域的新同事,周末除了宅家写代码,也想探索一下本地的科技氛围和休闲活…

2026/11/14 22:29:09

PTA基础编程题目集 7-23币值转换(C++语言实现)

摘要:本文是PTA编程题"币值转换"的题解,涵盖题目描述、输入输出格式及C语言实现,展示逐位处理数字与单位、处理中文零的财务大写转换算法。题目描述 输入一个整数(位数不超过9位)代表一个人民币值&#xff0…

2026/11/9 6:28:25

如何3步搞定全网资源下载?终极网络资源嗅探工具使用指南

如何3步搞定全网资源下载?终极网络资源嗅探工具使用指南 【免费下载链接】res-downloader 视频号、小程序、抖音、快手、小红书、直播流、m3u8、酷狗、QQ音乐等常见网络资源下载! 项目地址: https://gitcode.com/GitHub_Trending/re/res-downloader 你是否经…

2026/11/14 22:26:29

固安建筑电工证报考网上查询怕考不过白交培训费

固安建筑电工证报考网上查询怕考不过白交培训费 怕考不过白交培训费,这是很多准备报考 固安建筑电工证 的朋友心里最真实的声音。特别是在现在这个就业竞争激烈的环境下,花几千块报名,结果一不小心挂科,不仅钱打水漂,时间也浪费了。今天就来聊聊怎么…

2026/11/14 22:26:29

深圳考电工证在哪里 全国通用证书怎么选培训机构

深圳考电工证在哪里 全国通用证书怎么选培训机构 你是不是也遇到过这样的事?想在深圳考电工证,结果网上一搜“深圳考电工证在哪里”,弹出来的信息五花八门,有些机构承诺包过,有些说能全国通用,还有的压根不知道是正规渠道。这不,我认识的一个老电工朋…

2026/11/14 22:26:29

电工证是不是取消了?多久拿证能安心上岗

电工证是不是取消了?多久拿证能安心上岗 之前考的证在外省能不能转过来?这个问题在咱们电工圈里问得太多了。尤其是那些在外地打拼、后来回到老家的朋友们,常常因为证书问题犯愁。最近网上又传电工证是不是取消了,搞得不少兄弟心里没底,怕自己白费钱、白…

2026/11/14 22:21:29

大一能考高压电工证吗 高含金量证书怎么选

大一能考高压电工证吗 高含金量证书怎么选 你是不是也遇到过这种情况?刚大一就听说高压电工证含金量高,想早点考,但不知道去哪报名,怕被中介坑。其实,这正是很多同学的痛点,尤其是想提前规划职业发展的学生。别急,这篇文章会从南阳卧龙区水利工程从业…

2026/11/13 22:33:32

电工证丢失还能补吗?千万别踩坑,丢了证等于失业

电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。…

2026/11/14 0:06:39

土木特种工考证官方报名入口怎么找 之前考的证在外省能不能转过来

土木特种工考证官方报名入口怎么找 之前考的证在外省能不能转过来 之前考的证在外省能不能转过来?这个问题我太熟悉了,作为一名干了十几年的特种作业证书办理从业者,每年都会遇到不少像你一样在外地考了证,回来却发现无法直接使用的学员。别急,今天我就…

2026/11/14 0:06:39

电工证要多久多钱保姆级教程:工地太忙根本没时间复习考试

电工证要多久多钱保姆级教程:工地太忙根本没时间复习考试 工地太忙根本没时间复习考试,你不是一个人。在信阳浉河区,很多刚进入工地的电工都面临这样的困境:工作强度大,时间碎片化,根本没有系统复习考试的机会。但电工证是上岗的硬门槛,…

2026/11/13 22:32:11

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/13 12:14:39

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑