Rust in Everything
基于 tokio 1.54.1

同步原语

前面几部分里,叫醒任务的是驱动:socket 可读了,定时器到期了。tokio::sync 里的东西是另一种唤醒来源:一个任务 send、unlock、notify,另一个任务被叫醒。它们不依赖运行时的驱动,源码都在 sync/ 下,大部分在运行时之外也能用。

这一部分讲三件事:

  1. batch_semaphore:一个原子计数加一条侵入式等待链表。Semaphore、Mutex、RwLock 和有界 mpsc 的背压都建在它上面。只要有人在排队,计数就是 0,所以先来的一定先拿到。
  2. mpsc:发送端用一次 fetch_add 抢一个序号,写进 32 槽一块的链表;接收端独占链表头,读完的块尽量挂回尾部复用。有界和无界只差一个 Semaphore 实现。
  3. oneshot、watch、broadcast、Notify:一个状态字的 oneshot;版本号加读写锁的 watch;环形缓冲区的 broadcast;以及 Notify 到底会不会丢通知。
flowchart TB
  bs[batch_semaphore] --> sem[Semaphore]
  bs --> mutex["Mutex:1 个许可"]
  bs --> rw["RwLock:读 1 个,写全部"]
  bs --> bounded[有界 mpsc 的背压]
  list[block 链表] --> bounded
  list --> unbounded[无界 mpsc]
  notify[Notify] --> watch["watch:8 个 Notify"]
  notify --> closed["mpsc 的 closed()"]
  ring[环形缓冲区] --> bc[broadcast]
  state[一个状态字] --> os[oneshot]

这些原语的 future 大多会扣协作式预算(Notify 除外),预算本身见协作式调度预算。tokio::sync::Mutex 和 std::sync::Mutex 怎么选,放在「常见坑」里。

💬 关联讨论

发起讨论
加载中...