4-15.【OC】【锁】NSConditionLock 的状态值在工程中适合什么场景?

6 阅读3分钟

NSConditionLock 是对 NSCondition 的进一步封装。它最大的特点是:它不仅是一把锁,还自带一个“整数状态值(Condition Value)”。

在工程中,它最适合解决的是**“具有特定状态顺序依赖”**的并发任务。


1. 核心模型:基于状态的“条件准入”

普通的锁只有“开/关”两种状态。而 NSConditionLock 允许线程表达这样的意图:

“我不仅要拿到锁,我还要在 状态值为 X 的时候才拿到锁。”

它提供的 lock(whenCondition:) 方法会将加锁与条件检查原子化地结合在一起。


2. 实战场景 A:严格顺序的流水线任务

假设你有一个多步处理流程(如:解压 -> 解密 -> 渲染),这些任务分布在不同的并发队列中,但必须按顺序执行。

  • 场景: * 线程 A 处理“解压”,完成后将状态设为 1

    • 线程 B 等待状态 1,处理“解密”,完成后设为 2
    • 线程 C 等待状态 2,处理“渲染”。
  • 优势: 你不需要手动写 while 循环和 NSCondition 的等待逻辑,NSConditionLock 内部自动帮你处理了挂起与唤醒。


3. 实战场景 B:多生产者-单消费者的“批处理”

假设你正在编写一个日志上传器,只有当缓冲区填满(状态变为 Full)或者手动触发强制上传(状态变为 Force)时,消费线程才开始工作。

  • 逻辑: * 消费线程调用 lock(whenCondition: BUFFER_FULL)

    • 多个生产线程不断填充数据,直到某次写入发现缓冲区满了,调用 unlock(withCondition: BUFFER_FULL)
  • 优势: 相比信号量(Semaphore),它能更好地表达“满足某种特定业务逻辑状态”而非仅仅是“计数值”。


4. 实战场景 C:简单的读写控制或开关

虽然它不是专门的读写锁,但你可以用它来实现简单的**“模式切换”**。

  • 状态 0: 待机模式。

  • 状态 1: 工作模式。

  • 状态 2: 维护/清理模式。

    线程可以根据当前系统的整体状态,有选择地切入或挂起,而不需要在业务代码里写一堆 if/else


5. NSConditionLock vs NSCondition

特性NSConditionNSConditionLock
逻辑复杂度较高(需手动写 while 检查状态)较低(状态检查封装在 API 内部)
核心变量由开发者维护共享变量内部维护一个 NSInteger
性能略快略慢(内部有额外的状态管理开销)
语义化适合复杂的组合逻辑适合单一的线性状态机

6. 工程建议

虽然 NSConditionLock 很方便,但在现代 iOS 开发中,它的出场率较低,主要原因如下:

  1. 粒度太粗: 它只能基于一个整数进行同步。如果你的逻辑涉及多个变量(比如“数组不为空”且“网络已连接”),它就显得捉襟见肘。

  2. 性能开销: 它是基于 NSCondition 实现的,属于相对重量级的锁。

  3. 更优选择: * 简单的顺序依赖:使用 OperationQueueaddDependency:

    • 复杂异步流:使用 Combine 或 Swift 的 Async/Await

结论: 当你面临现成的、基于状态机的旧代码重构,或者需要一个非常直观的线性同步模型时,NSConditionLock 是最优雅的选择。