Rust in Everything
基于 rayon-core 1.13.0

任务与 Latch

rayon-core 的线程池里流动的只有两样东西:任务和信号。任务是 deque 里的一个元素,谁拿到谁执行;信号是「那个任务做完了」,等的人看到它才能往下走。前者是 job.rs(270 行),后者是 latch.rs(457 行)。这两个文件都是 pub(super),用户看不到,但 join、scope、spawn、broadcast、install 全都由它们拼成。

flowchart LR
  subgraph caller["发起方的栈帧"]
    sj["StackJob:latch + func + result"]
  end
  sj -->|"as_job_ref:擦掉类型"| jr["JobRef:pointer + execute_fn,16 字节"]
  jr -->|"push / inject"| dq["deque / Injector"]
  dq -->|"pop / steal"| ex["执行方:execute_fn(pointer)"]
  ex -->|"写 result,再 Latch::set"| sj
  caller -.->|"wait_until(latch):边等边干活"| sj

两章:

  1. JobRef 与几种 Job:Job trait 只有一个 unsafe fn execute(*const ());JobRef 是两个字的手写胖指针,类型和生命周期一起被擦掉,deque 里只需要一种元素类型;StackJob(join、install、broadcast)、HeapJob(spawn、scope.spawn)、ArcJob(spawn_broadcast)、JobFifo(spawn_fifo 的间接层)各自在哪里、什么时候释放;JobResult 三态;migrated 参数实际表示什么(实验 E14)。
  2. Latch 家族:Latch::set 为什么收 *const Self;CoreLatch 的 UNSET / SLEEPY / SLEEPING / SET 四态,以及它们怎么让「设置」和「睡下」两个动作在同一个原子变量上分出先后;SpinLatch、LockLatch、OnceLatch、CountLatch、LatchRef 各给谁用;每个 set 实现里「先读字段、后 set」的顺序。

一张对照表

用户 API任务类型放在哪等待方用的 latch等待方式
join 的 BStackJob本线程 dequeSpinLatchwait_until:边等边找活
池外调 install / join / scopeStackJob全局 InjectorLatchRef<LockLatch>(线程本地)Condvar 阻塞
在别的池里调 installStackJob目标池的 InjectorSpinLatch::cross在自己的池里边等边干活
scope.spawnHeapJob本线程 deque 或 InjectorCountLatch等的线程是 worker 就 wait_until;池外的 in_place_scope 用 LockLatch
spawnHeapJob同上没有,没人等—
spawn_fifoHeapJob 进 JobFifo,deque 里放指向 FIFO 的 JobRef本线程 deque 或 Injector没有—
broadcast每线程一个 StackJob每线程的广播队列CountLatch(经 LatchRef)同 scope
spawn_broadcast一个 ArcJob,每线程一个 JobRef每线程的广播队列没有—
线程池终止——OnceLatch(每线程一个 terminate)主循环 wait_until

这张表的每一行在 04 对外 API 里展开。等待方怎么「边等边干活」见 WorkerThread 主循环;等不到活之后怎么睡、SLEEPY / SLEEPING 两个状态怎么用,见 05 sleep 模块。

本部分的实验

#目录看什么章
E14exp-rayon/join-context/RAYON_NUM_THREADS=1 下所有闭包都在 0 号线程上跑,migrated() 仍可能是 true:从池外调用时 A、B 都是 true;A 里调 yield_local() 弹出 B 时 B 是 trueJobRef 与几种 Job

两章大部分内容靠读代码,实验只有这一个。latch 的正确性(「set 之后不碰」)没有办法用一次运行证明:读错了的版本在大多数运行里也不会出错,上游是靠 miri 发现的(见 Latch 家族里 a46e1f8 那一段)。

💬 关联讨论

发起讨论
加载中...