iOS - 自旋锁

ops/2025/1/8 22:12:02/

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

1. 性能考虑

上下文切换成本

// 自旋锁实现
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. 使用场景特点

短暂的临界区

// 属性访问的典型场景
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. 内存效率

结构简单

typedef struct {volatile int32_t value;  // 仅需要一个32位整数
} OSSpinLock;// 相比互斥锁的复杂结构
struct pthread_mutex_t {// ... 更复杂的内部结构// 包含条件变量、等待队列等
};

优势:

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

4. 适用的情况

理想场景

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

最佳实践:

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

5. 潜在问题

优先级反转

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

解决方案:

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

6. 使用建议

适合使用自旋锁的场景

// 1. 简单的原子操作
atomic_property.lock();
value = _property;
atomic_property.unlock();// 2. 快速的引用计数操作
spinlock.lock();
refCount++;
spinlock.unlock();

不适合使用自旋锁的场景

// 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
  • 复杂场景应考虑其他锁机制

http://www.ppmy.cn/ops/148570.html

相关文章

【JAVA】Java开发小游戏 - 简单的2D平台跳跃游戏 基本的2D平台跳跃游戏框架,适合初学者学习和理解Java游戏开发的基础概念

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默, 忍不住分享一下给大家。点击跳转到网站 学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……) 2、学会Oracle数据库入门到入土用法(创作中……) 3、手把…

在环境冲突情况下调整优先级以解决ROS Catkin构建中缺少模块的问题【ubuntu20.04】

在机器人操作系统(ROS)的开发过程中,构建工作空间时遇到各种依赖性问题是常见的挑战之一。尤其是在多Python环境共存的情况下,环境变量的冲突往往导致诸如缺少empy模块等错误。本文将详细介绍在ROS Noetic与Anaconda Python环境共…

apex安装

安装过程复杂曲折,网上说的很多办法,貌似成功了,实际还是没起作用。 先说成功过程,执行下面命令,安装成功(当然,前提是你要先配置好编译环境): (我的环境&a…

lenovo联想IdeaPad 15sIML 2020款(81WB)笔记本电脑原装出厂OEM预装系统Windows10镜像下载

适用机型 :【81WB】 链接:https://pan.baidu.com/s/1SF9uWaNdCKPkwKgsCWb18g?pwdh6qe 提取码:h6qe 联想原厂WIN系统自带所有驱动、带Recovery恢复重置、出厂主题壁纸、系统属性联机支持标志、系统属性专属LOGO标志、Office办公软件、联想…

Django REST framework 源码剖析-视图类详解(Views)

Django REST framework视图图解 视图类(View) ‌视图‌是DRF中处理用户请求的基本单元。它们可以是函数视图(FBV)或类视图(CBV)。函数视图使用函数来处理请求,而类视图则使用类来处理请求。类视…

大数据学习(33)-续集

今天开始重新更新大数据 -- 感谢大家的支持!!!

以太网连接,本地连接,宽带连接,无线WLAN连接;交换机和路由器

1、以太网连接,本地连接,宽带连接,无线WLAN连接区别 2、交换机和路由器区别

第 22 章 处理 XML

第 22 章 处理 XML 22.1 浏览器对 XML DOM 的支持 22.1.1 DOM Level 2 Core 正如第 12 章所述,DOM Level 2 增加了 document.implementation 的 createDocument()方法。有读者可能还记得,可以像下面这样创建空 XML 文档: let xmldom doc…