同步原语
本章介绍 ASCO 提供的同步原语。它们用于在多个并发执行流之间建立互斥与协调关系。
本章只描述行为与语义:你能做什么、它会怎样表现、以及常见用法。
目录
选型建议
何时使用 channel
channel 适合在并发执行流之间传递值,并通过等待来表达背压(缓冲满时发送等待,缓冲空时接收等待)。
何时使用 spinlock
spinlock 适合保护非常短的临界区:
- 修改一个小的共享状态(例如计数器、指针、短容器操作);
- 临界区内不进行可能长时间运行的操作。
注意:
- 不要在持有锁期间跨越
co_await。
何时使用 semaphore
semaphore 适合表达“许可”的语义:
- 并发限流(最多允许同时进行
N个工作); - 生产者/消费者式的资源计数(有资源才能继续)。
acquire() 是可等待操作:当许可不足时会等待直到有许可被释放。
何时使用 rwlock
rwlock 适合保护“读多写少”的共享状态:
- 多个 reader 同时读取是安全且有价值的;
- 写入虽然较少,但写入时需要与所有 reader 互斥;
- 你希望一旦 writer 开始等待,后续 reader 不再继续插队。
如果读写比例并不偏向读取,或者临界区极短,通常 mutex 会更直接。
何时使用 condition_variable
condition_variable 适合表达“等某个条件成立,然后由别的任务通知我继续”:
- 条件本身保存在外部共享状态里;
- 等待方通过 predicate 判断是否可以继续;
- 状态改变后,由生产者调用
notify_one()/notify(n)唤醒等待方;必要时也可以使用带 predicate 的通知重载做额外门控。
它本身不拥有被保护的数据,也不提供互斥;若 predicate 访问共享状态,调用方需要自行保证可见性与并发安全。
常见约定
- 用
try_*系列 API 表达“不等待的快速路径”;失败时走其它分支。 - 需要等待时,优先用明确的同步原语(例如
semaphore::acquire()),避免忙等。