completion、semaphore 与协作等待

这页讲的是:并发问题不总是“谁先拿锁”,很多时候更像“我先等你把那件事做完”或“这个资源同一时刻允许有限数量的人进入”。学这页的重点,是理解 completion 和 semaphore 更偏协作与限流,而不是单纯互斥。

这块是什么

completion、semaphore 与协作等待,讲的是当两个或多条执行路径之间需要约定“什么时候某件事算完成”“一次最多允许多少人进去”时,Linux 怎样用比互斥锁更贴合语义的同步工具来表达。它们常出现在初始化协作、后台工作完成通知、资源并发数量控制等场景里。

可以把它理解成:有时你需要的不是“把门锁死,只准一个人进”,而是“等装修队说完工再进屋”或者“这间机房同一时间最多进三个人”。

它负责什么

表达“等某事完成”

  • 让一条路径等待另一条路径把关键动作做完
  • 适合一次性完成通知或阶段性协作
  • 把“完成没完成”从口头约定变成正式同步关系
  • 让等待和唤醒更贴合业务时序

控制并发进入数量

  • 限制某类资源同一时刻被多少路径占用
  • 不一定要求完全互斥
  • 更适合表达配额和容量上限
  • 让同步语义更接近真实资源约束

减少语义错配

  • 不是所有等待关系都该拿互斥锁硬表示
  • 不同同步原语表达的问题不一样
  • 选错工具容易把代码写得既绕又脆弱
  • 让“为什么要等”比“怎么卡住别人”更清楚

为什么它不只是“另一种睡眠锁”

如果想得太简单会怎样真正关键在哪
把 completion 当普通锁会忽略它更像完成信号,而不是谁拥有临界区。它重点在“事情做完没”,不是“谁正在独占”。
把 semaphore 当 mutex 替身会错过它更适合表示有限并发配额。它不一定只允许一个人进。
所有协作都靠等待队列手拼代码语义会越来越散,读者不容易看出等待意图。这些原语的价值之一就是把协作模式显式表达出来。
觉得能等到就行会忽略超时、退出和生命周期可能把协作变复杂。协作等待也要考虑谁可能先走、谁可能永远不来。

关键概念

概念现在怎么理解
completion一种偏向“某件事完成后通知等待者”的同步工具。
semaphore一种更适合表达有限数量并发进入或资源配额的同步工具。
协作等待等待的重点不是抢临界区,而是等别的路径推进到某个阶段。
配额控制不是完全禁止并发,而是限制最多允许多少人同时使用。
完成通知后台或另一执行路径做完后,正式唤醒等待者继续往下走。

为什么重要

常见误解

它不负责什么

和其他模块的关系

相关模块关系
等待队列、睡眠与唤醒这页可以看作把更具体的协作等待模式,从通用等待机制里继续拆出来。
workqueue 与异步执行后台任务完成后如何通知前台继续,常常会落到这类协作关系上。
定时器、超时与延迟执行很多协作等待如果太久没结果,还要和超时边界一起考虑。
probe / remove / 生命周期初始化和退出常要等待某些异步动作真正完成,避免半拉子状态。

读完这页后,你应该能回答

后面适合继续问:completion 和等待队列最容易混在哪?为什么 semaphore 更像配额而不只是锁?协作等待在退出路径里最容易踩到哪类永远等不到的问题?