自旋锁的本质是持续占有cpu,直到获取到资源。与其他锁的忙等待的实现机制不同。

昨天有位开发者在 Github 上给我提了一个 issue,里面指出 OSSpinLock 在新版 iOS 中已经不能再保证安全了,并提供了几个相关资料的链接。我仔细查了一下相关资料,确认了这个让人不爽的 bug。

OSSpinLock 的问题

2015-12-14 那天,swift-dev邮件列表里有人在讨论 weak 属性的线程安全问题,其中有几位苹果工程师透露了自旋锁的 bug,对话内容大致如下:

新版 iOS 中,系统维护了 5 个不同的线程优先级/QoS: background,utility,default,user-initiated,user-interactive。高优先级线程始终会在低优先级线程前执行,一个线程不会受到比它更低优先级线程的干扰。这种线程调度算法会产生潜在的优先级反转问题,从而破坏了 spin lock。

具体来说,如果一个低优先级的线程获得锁并访问共享资源,这时一个高优先级的线程也尝试获得这个锁,它会处于 spin lock 的忙等状态从而占用大量 CPU。此时低优先级线程无法与高优先级线程争夺 CPU 时间,从而导致任务迟迟完不成、无法释放 lock。这并不只是理论上的问题,libobjc 已经遇到了很多次这个问题了,于是苹果的工程师停用了 OSSpinLock。

苹果工程师 Greg Parker 提到,对于这个问题,一种解决方案是用 truly unbounded backoff 算法,这能避免 livelock 问题,但如果系统负载高时,它仍有可能将高优先级的线程阻塞数十秒之久;另一种方案是使用 handoff lock 算法,这也是 libobjc 目前正在使用的。锁的持有者会把线程 ID 保存到锁内部,锁的等待者会临时贡献出它的优先级来避免优先级反转的问题。理论上这种模式会在比较复杂的多锁条件下产生问题,但实践上目前还一切都好。

libobjc 里用的是 Mach 内核的 thread_switch() 然后传递了一个 mach thread port 来避免优先级反转,另外它还用了一个私有的参数选项,所以开发者无法自己实现这个锁。另一方面,由于二进制兼容问题,OSSpinLock 也不能有改动。

最终的结论就是,除非开发者能保证访问锁的线程全部都处于同一优先级,否则 iOS 系统中所有类型的自旋锁都不能再使用了。

OSSpinLock 的替代方案

为了找到一个替代方案,我做了一个简单的性能测试,对比了一下几种能够替代 OSSpinLock 锁的性能。测试是在 iPhone6、iOS9 上跑的,代码在这里。我尝试了不同的循环次数,结果并不都一样,我猜这可能是与 CPU Cache 有关,所以这个结果只能当作一个定性分析。

可以看到除了 OSSpinLock 外,dispatch_semaphore 和 pthread_mutex 性能是最高的。有消息称,苹果在新系统中已经优化了 pthread_mutex 的性能,所以它看上去和 OSSpinLock 差距并没有那么大了。

开源社区的反应

苹果

查看 CoreFoundation 的源码能够发现,苹果至少在 2014 年就发现了这个问题,并把CoreFoundation 中的 spinlock 替换成了 pthread_mutex,具体变化可以查看这两个文件:CFInternal.h(855.17)CFInternal.h(1151.16)。苹果自己发现问题后,并没有更新 OSSpinLock 的文档,也没有告知开发者,这有些让人失望。

Google

google/protobuf 内部的 spinlock 被全部替换为 dispatch_semaphore,详情可以看这个提交:https://github.com/google/protobuf/pull/1060。用 dispatch_semaphore 而不用 pthread_mutex 应该是出于性能考虑。

其他项目

因为 OSSpinLock 出现这种问题的几率很小,也没有引起很大的重视,我所能找到的也只有 ReactiveCocoa在讨论这个问题。

相关链接

https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151214/000344.html

http://mjtsai.com/blog/2015/12/16/osspinlock-is-unsafe/

http://engineering.postmates.com/Spinlocks-Considered-Harmful-On-iOS/

https://twitter.com/steipete/status/676851647042203648

不再安全的 OSSpinLock的更多相关文章

  1. 深入理解 iOS 开发中的锁

    来源:伯乐在线 - 夏天然后 链接:http://ios.jobbole.com/89474/ 点击 → 申请加入伯乐在线专栏作者 摘要 本文的目的不是介绍 iOS 中各种锁如何使用,一方面笔者没有大 ...

  2. iOS中保证线程安全的几种方式与性能对比

    来源:景铭巴巴 链接:http://www.jianshu.com/p/938d68ed832c 一.前言 前段时间看了几个开源项目,发现他们保持线程同步的方式各不相同,有@synchronized. ...

  3. iOS 多线程之线程锁Swift-Demo示例总结

    线程锁是什么 在前面的文章中总结过多线程,总结了多线程之后,线程锁也是必须要好好总结的东西,这篇文章构思的时候可能写的东西得许多,只能挤时间一点点的慢慢的总结了,知道了线程之后要了解线程锁就得先了解一 ...

  4. Aspects 源码学习

    AOP 面向切面编程,在对于埋点.日志记录等操作来说是一个很好的解决方案.而 Aspects 是一个对于AOP编程的一个优雅的实现,也可以直接借助这个库来使用AOP思想.需要值得注意的是,Aspect ...

  5. iOS开发之用到的几种锁整理

    1. iOS中的互斥锁 在编程中,引入对象互斥锁的概念,来保证共享数据操作的完整性.每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问对象. 1.1 @sync ...

  6. iOS 中的各种锁

    在日常开发过程中,为了提升程序运行效率,以及用户体验,我们经常使用多线程.在使用多线程的过程中,难免会遇到资源竞争问题.我们采用锁的机制来确保线程安全. 线程安全 当一个线程访问数据的时候,其他的线程 ...

  7. OSSpinLockLock加锁机制,保证线程安全并且性能高

    在aspect_add.aspect_remove方法里面用了aspect_performLocked, 而aspect_performLocked方法用了OSSpinLockLock加锁机制,保证线 ...

  8. iOS AOP框架Aspects实现原理

    总结: Aspects 是对 类的继承结构isa.mataclass结构的调整和维护:相当于链表的节点插入和删除: 同时使用method Swizzling 对方法统一重定向: 同时使用类似代理的机制 ...

  9. Atomic原子操作原理剖析

    前言 绝大部分 Objective-C 程序员使用属性时,都不太关注一个特殊的修饰前缀,一般都无脑的使用其非默认缺省的状态,他就是 atomic. @interface PropertyClass @ ...

随机推荐

  1. UVA 11077 Find the Permutations 递推置换

                               Find the Permutations Sorting is one of the most used operations in real ...

  2. pjlib深入剖析和使用详解

    1. PJSIP简介 PJSIP的实现是为了能在嵌入式设备上高效实现SIP/VOIP.其主要特征包括:    1).极具移植性.(Extremely portable)                 ...

  3. iOS开发-Tools-CocoaPods

    CocoaPods是什么? 当你开发iOS应用时,会经常使用到很多第三方开源类库,比如JSONKit,AFNetWorking等等.可能某个类库又用到其他类库,所以要使用它,必须得另外下载其他类库,而 ...

  4. Nashorn——在JDK 8中融合Java与JavaScript之力--转

    原文地址:http://www.infoq.com/cn/articles/nashorn 从JDK 6开始,Java就已经捆绑了JavaScript引擎,该引擎基于Mozilla的Rhino.该特性 ...

  5. 我网站用session做的登录,为什么清除浏览器数据后还是得重新登录?session是存在服务器上的。

    答案一: 你清除了浏览器数据,相当于把cookie也清了,那么你的sessionId也就没有了,所以你再次请求的时候服务器无法根据你携带的sessionid来获取对应的session,所以说需要重新登 ...

  6. poj1170 - 转换成背包

    题目链接 有5种物品,给出每个物品的单价. 给出几个这些物品的组合和这个组合的价格.买组合要比一件件的买便宜. 问给定的购买计划最少花多少钱. ---------------------------- ...

  7. nf_conntrack: table full, dropping packet. 问题

    查出目前 ip_conntrack 记录最多的前十名 IP: # cat /proc/net/nf_conntrack|awk '{print $8}'|cut -d'=' -f 2|sort |un ...

  8. 模块 -logging

    模块 -logging 一:在控制台显示:默认 import logging logging.debug("debug") logging.info("debug&quo ...

  9. PID的原理

    来源:https://www.cnblogs.com/foxclever/p/8902029.html 在自动控制中,PID及其衍生出来的算法是应用最广的算法之一.各个做自动控制的厂家基本都有会实现这 ...

  10. Informatica环境搭建过程中一些问题-近期项目进了新人,在搭建环境中存在一些问题,之前都处理过一直没有整理,这次接着机会,把这些常见问题处理整理出来

    一.Informatica9.5.1创建资源库出错找不到libpmora8.so 错误如下: Database driver event...Error occurred loading librar ...