关于 @synchronized

来源:互联网 发布:大疆视频剪辑软件 编辑:程序博客网 时间:2024/05/29 15:07

本文翻译自 Ryan Kaplan 的 More than you want to know about @synchronized

http://yulingtianxia.com/blog/2015/11/01/More-than-you-want-to-know-about-synchronized/?

因为原文一些内容写的不太准确,我按照我的理解做出了批注和补充。

如果你已经使用 Objective-C 编写过任何并发程序,那么想必是见过 @synchronized这货了。@synchronized 结构所做的事情跟锁(lock)类似:它防止不同的线程同时执行同一段代码。但在某些情况下,相比于使用 NSLock 创建锁对象、加锁和解锁来说,@synchronized 用着更方便,可读性更高。

译者注:这与苹果官方文档对 @synchronized 的介绍有少许出入,但意思差不多。苹果官方文档更强调它“防止不同的线程同时获取相同的锁”,因为文档在集中介绍多线程编程各种锁的作用,所以更强调“相同的锁”而不是“同一段代码”。

如果你之前没用过 @synchronized,接下来有个使用它的例子。这篇文章实质上是谈谈有关我对 @synchronized实现原理的一个简短研究。

用到 @synchronized 的例子

假设我们正在用 Objective-C 实现一个线程安全的队列,我们一开始可能会这么干:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@implementation ThreadSafeQueue
{
NSMutableArray *_elements;
NSLock *_lock;
}

- (instancetype)init
{
self = [super init];
if (self) {
_elements = [NSMutableArray array];
_lock = [[NSLock alloc] init];
}
return self;
}

- (void)push:(id)element
{
[_lock lock];
[_elements addObject:element];
[_lock unlock];
}

@end

上面的 ThreadSafeQueue 类有个 init 方法,它初始化了一个 _elements 数组和一个 NSLock 实例。这个类还有个 push: 方法,它先获取锁、然后向数组中插入元素、最终释放锁。可能会有许多线程同时调用 push: 方法,但是 [_elements addObject:element] 这行代码在任何时候将只会在一个线程上运行。步骤如下:

  1. 线程 A 调用 push: 方法
  2. 线程 B 调用 push: 方法
  3. 线程 B 调用 [_lock lock] - 因为当前没有其他线程持有锁,线程 B 获得了锁
  4. 线程 A 调用 [_lock lock],但是锁已经被线程 B 占了所以方法调用并没有返回-这会暂停线程 A 的执行
  5. 线程 B 向 _elements 添加元素后调用 [_lock unlock]。当这些发生时,线程 A 的 [_lock lock] 方法返回,并继续将自己的元素插入 _elements

我们可以用 @synchronized 结构更简要地实现这些:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@implementation ThreadSafeQueue
{
NSMutableArray *_elements;
}

- (instancetype)init
{
self = [super init];
if (self) {
_elements = [NSMutableArray array];
}
return self;
}

- (void)increment
{
@synchronized (self) {
[_elements addObject:element];
}
}

@end

在前面的例子中,”synchronized block” 与 [_lock lock] 和 [_lock unlock] 效果相同。你可以把它当成是锁住self,仿佛 self 就是个 NSLock。锁在左括号 { 后面的任何代码运行之前被获取到,在右括号 } 后面的任何代码运行之前被释放掉。这爽就爽在妈妈再也不用担心我忘记调用 unlock 了!

你可以给任何 Objective-C 对象上加个 @synchronized。那么我们也可以在上面的例子中用@synchronized(_elements) 来替代 @synchronized(self),效果是相同的。

回到研究上来

我对 @synchronized 的实现十分好奇并搜了一些它的细节。我找到了一些答案,但这些解释都没有达到我想要的深度。锁是如何与你传入 @synchronized 的对象关联上的?@synchronized会保持(retain,增加引用计数)被锁住的对象么?假如你传入 @synchronized 的对象在 @synchronized 的 block 里面被释放或者被赋值为 nil 将会怎么样?这些全都是我想回答的问题。而我这次的收获,会要你好看

0 0
原创粉丝点击