“不公平”(Unfair)在这里是一个计算机科学术语,主要指该锁不保证“先来后到”的排队顺序(First-In-First-Out, FIFO) 。
在传统的“公平锁”中,如果线程 A、B、C 依次尝试获取锁,当锁释放时,系统必须按照 A -> B -> C 的顺序唤醒。而 os_unfair_lock 允许“插队”。
以下是它选择“不公平”策略的三个核心原因:
1. 减少上下文切换(Context Switch)的开销
这是最直接的性能考量。
- 公平锁的代价:当线程 A 释放锁时,系统必须挂起当前正在 CPU 上运行的线程,去唤醒并在内核中调度处于休眠状态的线程 B。这种上下文切换是非常昂贵的。
- 不公平锁的优势:如果线程 A 释放锁的那一刻,线程 D 正好在 CPU 上处于活跃状态并请求锁,
os_unfair_lock会直接把锁交给线程 D。 - 结果:省去了唤醒线程 B 的等待时间和切换成本,显著提升了系统的整体吞吐量。
2. 利用 CPU 缓存局部性(Cache Locality)
处于活跃状态的线程(正在 CPU 上运行的线程)其数据通常还在 L1/L2 缓存中。
- 如果让这个活跃线程“插队”获取锁并继续执行,它处理任务的速度会比一个刚从休眠中唤醒、缓存还是“冷”状态的线程快得多。
3. 配合“优先级继承”解决实际问题
在 iOS 的 os_unfair_lock 机制中,虽然它是“不公平”的,但它通过内核联动解决了安全性问题:
- 动态调节:虽然它允许活跃线程插队,但如果有一个高优先级线程(H)正在休眠等待这把锁,内核的调度算法会识别到这一点。
- 平衡:它并不是盲目地让弱者永远等待,而是在“性能最大化”和“防止线程饥饿”之间寻找平衡点。通过优先级继承,它确保了持有锁的低优先级线程能尽快完成任务并放锁。
总结
os_unfair_lock 之所以被设计成“不公平”,是因为在现代移动操作系统(如 iOS)中,吞吐量和低延迟比绝对的公平更重要。
| 维度 | 公平锁 (如某些 Semaphore 实现) | 不公平锁 (os_unfair_lock) |
|---|---|---|
| 分配原则 | 严格排队,先到先得 | 谁在运行谁优先(插队) |
| 性能 | 较低(上下文切换频繁) | 极高(利用当前 CPU 时间片) |
| 线程饥饿 | 理论上不会发生 | 可能发生(但 iOS 通过调度算法缓解) |
关联到您的日志
回到您最初提供的 slowlog_0 堆栈 ,可以看到大量操作都在主线程(com.apple.main-thread)排队执行 。如果在这种高负载的初始化逻辑中使用传统的公平锁,频繁的线程唤醒和上下文切换会进一步拖慢 iPhone 6S Plus 的响应速度 。而 os_unfair_lock 的“不公平”特性,正是为了在这种高竞争环境下榨取每一毫秒的性能。