Solaris 的旋转门(Turnstile):把互斥锁的等待者状态挪到锁外面,还顺带解决优先级反转
来源: rdmsr.github.io — 2026-09-08
概述
这篇技术长文把 Solaris 里一个少见被讨论、却悄悄传遍全世界的发明讲透了:turnstile(旋转门)。背景是 Solaris 为了接近软实时的延迟表现,大量采用阻塞式互斥锁,但阻塞锁带来两个问题——每个锁若都要内建完整的「谁持有、谁在等、怎么叫醒」簿记,代价太高;以及低优先级持锁者会挡住高优先级任务的优先级反转。优先级继承的思路是让持锁者临时借走高优先级的优先级,并沿 owner 链多跳传播。turnstile 的精妙在于把这份状态从锁里拿出来:每个线程创建时就自带一个 turnstile,一旦被阻塞就把它「捐赠」给所等的锁,内核用锁地址的哈希表来定位它,释放时线程再从 freelist 随便取一个。正因为这套空间节省思想,它如今出现在 Illumos、macOS 的 XNU、FreeBSD、NetBSD 甚至 Go 运行时与 WebKit 的 WTF::ParkingLot 里——后者把昂贵的等待机制同样从锁里剥了出来。
核心要点
- 阻塞互斥锁要内建簿记状态而变「大」,对细粒度加锁是浪费——大多数锁大多无竞争
- 优先级反转的根源:高优先级任务被低优先级持锁者挡住,任意中优先级任务都能抢占它
- turnstile 是与竞争锁关联的数据结构,记录等待者并携带沿 owner 链传播优先级的所需信息
- 每个线程创建时自带一个 turnstile,被阻塞时捐赠给所等之锁,用锁地址哈希定位
- 单继承者使其难以优雅应对读写锁等多所有者场景,只能靠启发式或干脆放弃继承
- 同一基本思想也见于 Go 运行时与 WTF::ParkingLot,它们同样把等待机制移出锁对象
金句
The difference between a turnstile and the lock is that the expensive waiter machinery lives outside the lock itself.
👍 0
👎 0
返回 Lobsters 首页