iOS - 自旋锁

在 Objective-C 运行时中大量使用自旋锁,主要有以下几个原因:

1. 性能考虑

上下文切换成本

objectivec 复制代码
// 自旋锁实现
static ALWAYS_INLINE void OSSpinLockLock(volatile OSSpinLock *lock) {
    do {
        while (lock->value != 0) {
            __asm__ volatile ("pause");  // 不释放CPU,继续尝试
        }
    } while (!OSAtomicCompareAndSwap32(0, 1, &lock->value));
}

// 相比互斥锁的实现
pthread_mutex_lock(&mutex);   // 可能导致线程休眠和上下文切换
// ... 
pthread_mutex_unlock(&mutex);

优势:

  1. 避免了线程上下文切换的开销
  2. 适合短期持有的场景
  3. 在多核处理器上效率更高

2. 使用场景特点

短暂的临界区

objectivec 复制代码
// 属性访问的典型场景
id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
    if (!atomic) return *((id *)((char *)self + offset));
    
    spinlock_t& slotlock = PropertyLocks[GOODHASH(offset)];
    slotlock.lock();    // 持锁时间极短
    id value = *((id *)((char *)self + offset));
    slotlock.unlock();
    return value;
}

特点:

  1. 锁的持有时间非常短
  2. 竞争不激烈
  3. 代码路径简单

3. 内存效率

结构简单

objectivec 复制代码
typedef struct {
    volatile int32_t value;  // 仅需要一个32位整数
} OSSpinLock;

// 相比互斥锁的复杂结构
struct pthread_mutex_t {
    // ... 更复杂的内部结构
    // 包含条件变量、等待队列等
};

优势:

  1. 内存占用小
  2. 缓存友好
  3. 初始化成本低

4. 适用的情况

理想场景

objectivec 复制代码
// 引用计数操作
inline bool objc_object::sidetable_tryRetain() {
    SideTable& table = SideTables()[this];
    bool result = false;
    
    table.lock();   // 快速的加锁解锁
    // 简单的引用计数操作
    table.unlock();
    
    return result;
}

最佳实践:

  1. 临界区执行时间短
  2. 线程等待时间短
  3. CPU资源充足

5. 潜在问题

优先级反转

objectivec 复制代码
// 可能出现的问题场景
while (lock->value != 0) {
    // 如果持有锁的是低优先级线程
    // 而等待的是高优先级线程
    // 可能导致优先级反转
    __asm__ volatile ("pause");
}

解决方案:

  1. iOS 10 后系统更多使用 os_unfair_lock
  2. 对于复杂场景使用互斥锁
  3. 需要考虑优先级时使用其他锁机制

6. 使用建议

适合使用自旋锁的场景

objectivec 复制代码
// 1. 简单的原子操作
atomic_property.lock();
value = _property;
atomic_property.unlock();

// 2. 快速的引用计数操作
spinlock.lock();
refCount++;
spinlock.unlock();

不适合使用自旋锁的场景

objectivec 复制代码
// 1. 复杂的操作
lock.lock();
[self complexOperation];  // 耗时操作
lock.unlock();

// 2. 可能阻塞的操作
lock.lock();
[self operationMayBlock];  // 可能阻塞
lock.unlock();

7. 总结

自旋锁在 Objective-C 运行时中的广泛使用是基于以下考虑:

  1. 性能优化:避免上下文切换
  2. 场景匹配:适合短期、快速的操作
  3. 资源效率:内存占用小,初始化快
  4. 实现简单:容易维护和调试
  5. 硬件友好:在现代多核处理器上表现良好

但需要注意:

  • 不适合长时间持有
  • 要考虑优先级反转问题
  • iOS 10 后推荐使用 os_unfair_lock
  • 复杂场景应考虑其他锁机制
相关推荐
andyweike5 小时前
Swift
开发语言·ios·swift
茶底世界之下6 小时前
白杯偏蓝,色温调到哪里该停?Awaking 两版正式导出
ios
2501_915921439 小时前
KXBuild CI 实操,Windows/Linux 服务器接入 Jenkins 打包 iOS IPA
服务器·windows·vscode·ios·ci/cd·个人开发·敏捷流程
狗凯之家源码网9 小时前
iOS C2 V2 与 Python FastAPI 全链路远控系统深度评测
python·ios·fastapi
看浪的路人10 小时前
第6讲:Streaming 优化——告别“转圈圈“的用户体验
ios·iphone·xcode
传奇开心果编程21 小时前
【Flutter踩坑排雷】第7课:巨型 build 函数坑|全部 UI 写在同一个 build,维护难、隐性异常
android·flutter·ios·移动开发·跨平台·dart·声明式ui
瓦瓦gogo1 天前
第一次了解 iOS 开发:从 Swift、SwiftUI 到公共组件
ios·swiftui·swift
Liben1 天前
Weex开发踩坑记录
android·前端·ios
season_zhu1 天前
Skills For Real Engineers 系列之三:需求聊清楚了,怎么一步步走主流程,做到交付?
ios·ai编程
茶底世界之下1 天前
窗边花瓶太暗?用 Awaking 看提亮室内的代价
ios