linux线程同步图解

发布时间:2026/10/29 12:05:42

linux线程同步图解 线程同步方法图解从多人厨房到播放器状态机线程同步不是“加锁”两个字能概括的事它更像给一群人协作制定规则谁能进、谁要等、什么时候一起走、谁来统一排队处理。为什么需要线程同步多人厨房的混乱现场想象一个后厨同时来了 4 个厨师。大家都想快点出菜但厨房里只有一口锅、三个灶台、一张菜单、一个出餐铃。如果没有协作规则会发生什么厨房里的混乱程序里的对应问题需要的同步语义两个人同时往同一口锅里倒菜多线程同时修改同一份数据互斥访问厨师一直问“饭熟了吗”线程忙等某个条件条件通知10 个人抢 3 个灶台并发任务超过资源容量限制并发数旅行团没等齐就发车多个线程阶段不同步阶段对齐开业剪彩被办了 5 次全局初始化重复执行只执行一次计数牌被同时按简单变量读改写冲突原子操作所有人都改菜单复杂状态机被多线程打乱消息排队串行化下面按“为什么要发明它 → 它是什么 → 什么时候用 → 怎么写”的顺序把常见同步方式串起来。1. Mutex为什么需要“一把钥匙”最朴素的问题是同一份数据同一时间只能有一个线程修改。如果两个线程同时执行balance balance 1看起来只是一行代码机器层面却可能拆成“读值 → 加一 → 写回”。两个线程读到同一个旧值就会丢一次更新。Mutex 的规则像厨房钥匙谁拿到钥匙谁进厨房做完必须还钥匙。维度说明解决的问题多线程同时读写同一份共享数据核心 APIpthread_mutex_init、pthread_mutex_lock、pthread_mutex_unlock、pthread_mutex_destroy典型场景保护结构体字段、全局表、链表、队列、状态变量优点语义简单适合大多数共享数据保护缺点锁粒度过大会降低并发忘记 unlock 会死锁示例保护共享计数器。#includepthread.hstaticpthread_mutex_tmutexPTHREAD_MUTEX_INITIALIZER;staticintcounter0;voidadd_one(void){pthread_mutex_lock(mutex);counter;pthread_mutex_unlock(mutex);}使用 Mutex 的核心不是“把所有代码都锁住”而是先问清楚哪一小段代码在访问共享状态只把这段临界区锁住。2. Condition Variable为什么需要“饭熟铃”Mutex 能保证“同一时间只有一个人改锅”但它解决不了另一个问题条件没满足时线程应该怎么等比如消费者线程要从队列取数据。队列为空时它不应该一直循环检查因为这会浪费 CPU。更好的方式是条件不满足就睡觉生产者放入数据后按铃叫醒它。Condition Variable 通常不单独使用而是和 Mutex、状态变量一起出现。组成作用为什么不能省Mutex保护条件对应的共享状态防止检查条件和修改条件并发打架State真实条件例如ready、queue_size、failedCond 只是通知本身不保存业务状态Cond让等待线程睡眠/唤醒避免忙等浪费 CPU经典写法一定是while不是if#includepthread.h#includestdbool.hstaticpthread_mutex_tmutexPTHREAD_MUTEX_INITIALIZER;staticpthread_cond_tcondPTHREAD_COND_INITIALIZER;staticbool readyfalse;voidwait_until_ready(void){pthread_mutex_lock(mutex);while(!ready){pthread_cond_wait(cond,mutex);}pthread_mutex_unlock(mutex);}voidmark_ready(void){pthread_mutex_lock(mutex);readytrue;pthread_cond_broadcast(cond);pthread_mutex_unlock(mutex);}为什么要用while因为线程可能被误唤醒也可能多个线程一起醒来后只有一个线程真正拿到资源。醒来以后重新检查条件是条件变量的基本礼仪。3. Semaphore为什么需要“多个停车位”有些资源不是只能一个线程用而是最多允许 N 个线程同时用。比如 3 个数据库连接、4 个解码任务名额、8 个下载槽位。这时 Mutex 太严格Barrier 又不对味。Semaphore 更像停车场有空位就进没空位就等离开时释放一个空位。维度说明解决的问题控制最多 N 个线程同时访问某类资源核心 APIsem_init、sem_wait、sem_post、sem_destroy典型场景连接池、任务并发数限制、资源池、队列容量控制优点自带计数表达“多个名额”很自然缺点不直接保护复杂共享状态wait/post配对错误会泄漏名额示例最多允许 3 个任务同时执行。#includesemaphore.hstaticsem_tslots;voidinit_slots(void){sem_init(slots,0,3);}voidrun_task(void){sem_wait(slots);/* Do work with limited resource. */sem_post(slots);}Semaphore 的重点是“名额”不是“所有权”。如果你要保护某个结构体内部的一致性仍然优先考虑 Mutex。4. Barrier为什么需要“人齐再发车”有些问题不是抢资源也不是等某个状态而是这一批线程都必须完成当前阶段然后才能进入下一阶段。旅行团最容易理解导游可以允许大家自由活动但下一段行程必须等所有人回到车上再开始。维度说明解决的问题固定数量线程在阶段边界集合核心 APIpthread_barrier_init、pthread_barrier_wait、pthread_barrier_destroy典型场景多线程压测同时起跑、分块计算每轮汇合、复现竞态问题优点语义直接特别适合“等齐”缺点参与线程数要固定有人不来就可能一直等示例4 个线程准备完成后同时开始。#includepthread.h#includestdio.h#defineN4staticpthread_barrier_tbarrier;void*worker(void*arg){longid(long)arg;printf(worker %ld ready\n,id);intretpthread_barrier_wait(barrier);if(retPTHREAD_BARRIER_SERIAL_THREAD){printf(all workers are ready\n);}printf(worker %ld start\n,id);returnNULL;}Barrier 的判断口诀是等人数用 Barrier等条件用 Cond。5. Once为什么需要“只剪彩一次”很多库都有全局表、缓存、单例对象。它们只需要初始化一次但可能被多个线程同时调用。如果每个入口都写一套if (!inited) init();就很容易遇到两个线程同时看到inited false然后重复初始化。维度说明解决的问题多线程环境下保证初始化函数只执行一次核心 APIpthread_once()C 可用std::call_once()典型场景全局查表初始化、单例对象创建、库级静态资源准备优点比自己手写双重检查更安全、更清晰缺点只适合一次性初始化不适合反复启停的状态示例全局表只初始化一次。#includepthread.hstaticpthread_once_tonce_controlPTHREAD_ONCE_INIT;staticintglobal_table[256];staticvoidinit_global_table(void){for(inti0;i256;i){global_table[i]i*i;}}intget_table_value(intindex){pthread_once(once_control,init_global_table);returnglobal_table[index];}如果你的全局数据“初始化后只读”pthread_once()往往比自己加一把全局锁更贴切。6. Atomic为什么需要“电子计数牌”有时共享状态很小只是一个计数器、一个标志位、一个引用计数。为了这么小的操作每次都进 Mutex可能显得笨重。Atomic 的目标是让单个变量的某些操作不可分割比如原子加一、原子读写、原子交换。维度说明解决的问题单个变量的并发读写和读改写核心 APIC11_Atomic、atomic_fetch_add、atomic_load、atomic_store等典型场景引用计数、统计计数、简单 ready flag、无锁结构基础字段优点开销小不一定阻塞线程缺点不适合保护多个字段之间的一致性内存序理解成本高示例原子引用计数。#includestdatomic.hstaticatomic_int ref_count0;voidretain(void){atomic_fetch_add_explicit(ref_count,1,memory_order_relaxed);}intrelease(void){returnatomic_fetch_sub_explicit(ref_count,1,memory_order_acq_rel)-1;}Atomic 适合“小而明确”的同步问题。只要你发现自己想同时维护多个字段的不变量例如state queue size就应该重新考虑 Mutex 或消息队列。7. Message Queue为什么要把“冲进去改状态”变成“排队办事”复杂系统里真正难的往往不是一个变量而是一整套状态机。比如播放器可能同时收到播放、暂停、seek、释放资源、网络回调、解码完成回调。如果这些线程都直接改播放器内部状态状态很快会变成一团乱麻。Message Queue 的思路是外部线程不要直接改核心状态只把命令投递到队列由一个专门线程按顺序处理。维度说明解决的问题多线程同时驱动复杂状态机导致顺序混乱核心组件线程安全队列、消息结构、事件循环、退出消息典型场景UI 线程、播放器控制线程、网络事件处理、Actor 模型优点把复杂状态集中到一个线程顺序清晰缺点有排队延迟需要设计消息优先级、退出和取消语义示例用队列思想串行处理命令。下面代码省略了队列实现只展示线程模型。enumCommandType{CMD_PLAY,CMD_PAUSE,CMD_SEEK,CMD_QUIT,};structCommand{enumCommandTypetype;longvalue;};void*event_loop(void*arg){for(;;){structCommandcmdqueue_pop_blocking();if(cmd.typeCMD_QUIT){break;}handle_command_in_owner_thread(cmd);}returnNULL;}它的本质不是“没有锁”而是把锁藏在队列边界把核心状态从“多线程直接修改”改成“单线程按序修改”。8. RWLock 和 SpinLock两个补充工具除了上面几种工程里还经常见到读写锁和自旋锁。工具为什么出现适合场景不适合场景pthread_rwlock_t读多写少时普通 Mutex 会让读者互相等待配置表、路由表、读多写少缓存写很多、读写关系复杂、需要严格公平性pthread_spinlock_t临界区极短时睡眠/唤醒成本可能比等待更高内核态或非常底层的短临界区用户态长等待、可能被调度出去的线程、移动端省电场景RWLock 像图书馆规则很多人可以同时读同一本书但有人要改书时其他人要先停下。SpinLock 像排队时一直站着盯门不睡觉。它可能很快也可能非常浪费 CPU所以普通业务代码不要优先选它。9. 最后一起对比先归类再选工具选同步方式时不要从“我要加什么锁”开始而要从“我到底在等什么 / 保护什么”开始。问题类型推荐工具生活类比一句话判断共享数据只能一个线程改Mutex厨房钥匙我要保护一段临界区读多写少共享数据RWLock图书馆读写规则多个读者可并发写者独占等某个条件变成真Cond State饭熟铃我等的是ready/failed/queue not empty最多 N 个线程同时用资源Semaphore停车位我等的是资源名额固定 N 个线程都到达Barrier旅行团发车我等的是人数到齐初始化只执行一次Once开业剪彩我怕重复初始化单变量小操作Atomic电子计数牌我只改一个计数或 flag复杂状态机按顺序处理Message Queue取号窗口我想把并发输入串行化极短临界区且能接受忙等SpinLock站着盯门我确认等待非常短10. 常见选错场景错误选择典型表现更好的选择用 Barrier 等后台初始化完成如果后台失败等待方不知道怎么退出cond ready/failed用 Atomic 维护多个字段单个字段都原子但整体状态不一致Mutex 或消息队列用 Mutex 限制并发下载数变成一次只能下载一个浪费并发能力Semaphore用 Cond 但没有状态变量丢通知后线程可能永远睡眠Cond 必须绑定 state用 SpinLock 包住耗时 I/OCPU 空转耗电且拖慢系统Mutex 或异步队列多个线程直接改状态机偶现顺序错乱难复现Message Queue / owner thread11. 记忆口诀可以把线程同步记成一套餐厅规则口诀对应工具抢同一口锅用 Mutex保护共享资源等饭熟铃响用 Cond等条件变化看还有几个灶台用 Semaphore控制并发名额人齐再发车用 Barrier阶段对齐剪彩只一次用 Once一次性初始化小计数别上大锁用 Atomic单变量原子操作菜单统一到窗口用 Queue复杂状态串行化线程同步不是为了“让程序看起来安全”而是为了让并发协作有明确规则。规则越贴近问题本身代码越简单bug 也越少。
延伸阅读

更多相关文章

2026/10/29 17:26:09

Ycoto3--layer(TODO)

Yocto 的 BitBake 引擎在解析 Layer 时,本质上只是按照 bblayers.conf 指定的顺序,去遍历每个 Layer 里的 conf/layer.conf,然后把里面所有的 .bb(Recipe)、.bbappend(追加配置)、.conf&#xf…

2026/10/27 19:52:22

Capture软件原理图输出网表常见错误解析笔记

Capture软件原理图输出网表常见错误解析笔记前言一、 排错第一步:找到并读懂 netlist.log1.1 报错触发场景1.2 日志文件在哪里?二、 10大常见错误详解与修复❌ 错误1:重复的网络名称(Duplicate Net Name)❌ 错误2&…

2026/10/29 17:28:07

大学生记账系统:SpringBoot+Vue轻量级金融数据流实践

简介:本资源是一套面向计算机专业本科生的高分毕业设计项目——大学生智能消费记账系统,聚焦学生日常财务管理痛点,提供从需求分析到部署运行的全流程实践范例,适用于毕设选题、课程设计及Java全栈开发入门学习。压缩包共374个文件…

2026/10/29 17:28:07

头脑风暴法落地指南:从发散到收敛的高效会议设计

上一次让我真正意识到头脑风暴法难在哪,是一场不到四十分钟就散场的会。当时我跟着一个产品小组做需求梳理,会议室里坐了十二个人,白板擦得干干净净,议题写在正中间,结果前二十分钟谁都不愿意先说,中间十分…

2026/10/29 17:28:07

CBAC与认证代理:中低端设备边界访问控制实战

做边界防护的同行大多遇到过这种尴尬:手上一台中低端路由式设备,功能表里既没有像样的区域防火墙模块,也没预算上专门的策略平台,但业务方要求很明确——外面不能随便进来,里面出去要留痕、要能追溯。这种时候 CBAC 和…

2026/10/29 17:28:07

大学生记账系统毕设实战:SpringBoot+Vue+MySQL全栈开发

简介:这是一套面向计算机专业本科生的高分毕业设计级智能记账系统,聚焦大学生日常消费管理痛点,提供从需求分析到部署运行的全流程实践范例,适用于毕设、课程设计及Java全栈开发入门学习。资源包共374个文件,15.51MB&a…

2026/10/29 17:28:07

AI安全博弈:防御者思维失效,攻击面重构与防御杠杆

他们总说,防御者拥有时间优势——攻击者必须每击必中,防守方只需挡住一次。但我在AI安全领域待得越久,越觉得这句话正在失效。尤其是看到2024年网鼎杯AI安全相关赛题和那些公开的WriteUp之后,我心里那个一直盘旋的念头更清晰了&am…

2026/10/29 17:23:05

数据库视图与索引原理及优化实战解析

1. 数据库视图与索引经典题解析在数据库管理与优化领域,视图和索引是两个最基础也最容易被误解的概念。我见过太多开发者在面试或实际工作中,对这两者的理解停留在表面层次。今天我们就来彻底拆解这两个技术点,通过典型问题分析它们的底层原理…

2026/10/29 17:05:52

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/29 17:06:02

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/29 17:06:13

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/29 0:03:42

学生选课系统DFD图绘制指南:边界划分与分层校验实战

简介:文档以顶层与第一层DFD图为核心,完整刻画学生选课系统的逻辑模型,面向软件工程课程设计、系统分析学习及毕设前期建模人群。顶层图界定系统边界,外部实体包括管理员、教师和学生三类角色;第一层图进一步细化用户登…

2026/10/29 0:03:42

JIRA敏捷落地:Scrum角色权限、Sprint与燃尽图避坑指南

简介:围绕“基于JIRA的敏捷开发项目管理”这一主题,面向产品负责人、Scrum Master及研发测试成员,梳理Scrum角色分工、迭代流程与JIRA工具配置的对应关系,适合初、中级团队导入敏捷管理时参考。压缩包共1个docx文件,大…

2026/10/29 0:03:42

SEMI S8人机工程验收实战:从条款拆解到现场实测的完整指南

简介:面向半导体设备设计、制造与运维工程师及安全合规人员,这份资料聚焦SEMI标准体系下的设备安全规范,重点收录SEMI S8-0308《半导体制造设备人体工程学工程安全指南》。内容围绕设备设计原则、错误与事故预防、人体工程学适配三大主线展开…

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

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

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