【问题标题】:Objective-C __block keyword and thread-safetyObjective-C __block 关键字和线程安全
【发布时间】:2012-02-26 07:46:08
【问题描述】:

我想知道如何在方法的上下文中访问__block 合格的线程安全变量。

例子:

__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 变量可能是 同时从不同的线程访问。

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

【问题讨论】:

  • 我不相信 __block 在这里是必要的,因为您没有更改 dictionary 所指的内容,只是对象的内部属性。我不确定您的并发问题,缺少简单地使用串行队列或将不安全操作包装在另一个分派到单个串行队列的块中的明显解决方案。

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


【解决方案1】:

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

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

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

【讨论】:

  • 在 ARC 模式下,dictionary 保留。以下是关于此的更多信息:mikeash.com/pyblog/…(参见“块”部分)
【解决方案2】:

这是不是线程安全的,但与 __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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-04
    • 1970-01-01
    • 2012-08-19
    • 2015-03-30
    • 1970-01-01
    相关资源
    最近更新 更多