专栏名称: SwiftGG翻译组
iOS 开发
目录
相关文章推荐
51好读  ›  专栏  ›  SwiftGG翻译组

构建一个 @synchronized

SwiftGG翻译组  · 掘金  · ios  · 2018-07-31 08:42

正文

阅读 19

构建一个 @synchronized

原文链接:https://swift.gg/2018/07/30/friday-qa-2015-02-20-lets-build-synchronized/
作者:Mike Ash
译者: Sunnyyoung
校对: 智多芯
定稿: numbbbbb CMB

上一篇文章讲了线程安全,今天这篇最新一期的 Let's Build 我会探讨一下如何实现 Objective-C 中的 @synchronized 。本文基于 Swift 实现,Objective-C 版本大体上也差不多。

回顾

@synchronized 在 Objective-C 中是一种控制结构。它接受一个对象指针作为参数,后面跟着一段代码块。对象指针充当锁,在任何时候 @synchronized 代码块中只允许有一个线程使用该对象指针。

这是一种使用锁进行多线程编程的简单方法。举个例子,你可以使用 NSLock 来保护对 NSMutableArray 的操作:

NSMutableArray *array;
NSLock *arrayLock;

[arrayLock lock];
[array addObject: obj];
[arrayLock unlock];
复制代码

也可以使用 @synchronized 来将数组本身加锁:

@synchronized(array) {
    [array addObject: obj];
}
复制代码

我个人更喜欢显式的锁,这样做既可以使事情更清楚, @synchronized 的性能没那么好,原因如下图所示。但它( @synchronized )使用很方便,不管怎样,实现起来都很有意思。

原理

Swift 版本的 @synchronized 是一个函数。它接受一个对象和一个闭包,并使用持有的锁调用闭包:

func synchronized(obj: AnyObject, f: Void -> Void) {
    ...
}
复制代码

问题是,如何将任意对象变成锁?

在一个理想的世界里(从实现这个函数的角度来看),每个对象都会为锁留出一些额外空间。在这个额外的小空间里 synchronized 可以使用适当的 lock unlock 方法。然而实际上并没有这种额外空间。这可能是件好事,因为这会增大对象占用的内存空间,但是大多数对象永远都不会用到这个特性。

另一种方法是用一张表来记录对象到锁的映射。 synchronized 可以查找表中的锁,然后执行 lock unlock 操作。这种方法的问题是表本身需要保证线程安全,它要么需要自己的锁,要么需要某种特殊的无锁数据结构。为表单独设置一个锁要容易得多。

为了防止锁不断累积常驻,表需要跟踪锁的使用情况,并在不再需要锁的时候销毁或者复用。

实现

要实现将对象映射到锁的表, NSMapTable 非常合适。它可以把原始对象的地址设置成键(key),并且可以保存对键(key)和值(value)的弱引用,从而允许系统自动回收未被使用的锁。

let locksTable = NSMapTable.weakToWeakObjectsMapTable()
复制代码

表中存储的对象是 NSRecursiveLock 实例。因为它是一个类,所以可以直接用在 NSMapTable 中,这点 pthread_mutex_t 就做不到。 @synchronized 支持递归语义,我们的实现一样支持。

表本身也需要一个锁。自旋锁(spinlock)在这种情况下很适合使用,因为对表的访问是短暂的:

var locksTableLock = OS_SPINLOCK_INIT
复制代码

有了这个表,我们就可以实现以下方法:

func synchronized(obj: AnyObject, f: Void -> Void) {
复制代码

它所做的第一件事就是在 locksTable 中找出与 obj 对应的锁,执行操作之前必须持有 locksTableLock 锁:

OSSpinLockLock(&locksTableLock)
var lock = locksTable.objectForKey(obj) as! NSRecursiveLock?
复制代码

如果表中没有找到对应锁,则创建一个新锁并保存到表中:

if lock == nil {
    lock = NSRecursiveLock






请到「今天看啥」查看全文