Objective-C __block关键字和线程安全

时间:2012-02-26 07:46:09

标签: objective-c cocoa-touch cocoa objective-c-blocks cocoa-design-patterns

我想知道如何在方法的上下文中访问__block限定的var线程安全。

示例:

__block NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];

for (int i=0; i<20; i++) {
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        [dictionary setObject:@"test" forKey:@"test"];
    }];
    [someConcurrentQueue addOperation:operation];
}

此处将操作添加到并发队列中,dictionary var可能是 同时从不同的线程访问。

这样安全吗?如果没有,我该如何访问dictionary安全?

2 个答案:

答案 0 :(得分:5)

正如UIAdam在评论中所说,__block在这里没有为你做任何事情;你正在改变字典,而不是分配给变量。该变量将继续永远指向同一个字典。

事实上,__block实际上可能会对您造成伤害,因为这意味着该块不会捕获该变量。如果您不使用ARC,这意味着不会保留字典,并且该块可能很快就会向死对象发送消息。我不确定ARC是否改变了这一点。无论如何,你应该让__block离开这个变量;如果不出意外,代码会在没有它的情况下更明确地表达您的意图。

关于你的实际问题,关于线程安全,这段代码不安全。 According to the Thread-Safety Summary,可变集合类不是线程安全的:您必须一次只从一个线程向可变集合发送消息。同步将是一种方式; setting the queue's max concurrent operation count到1将是另一个。

答案 1 :(得分:4)

这是线程安全但与__block关键字无关,因为您只是阅读但不写入。

使线程安全的最简单方法是使用@synchronized关键字

__block NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];

for (int i=0; i<20; i++) {
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        @synchronized(dictionary) {
            [dictionary setObject:@"test" forKey:@"test"];
        }
    }];
    [someConcurrentQueue addOperation:operation];
}

或者您可以使用NSLock或任何类型的锁定

应阅读此内容以获取更多信息 https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html