Ключевое слово Objective-C __block и безопасность потока - PullRequest
3 голосов
/ 26 февраля 2012

Мне интересно, как я могу сделать доступ к __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 потенциально может быть доступ из разных потоков одновременно.

Это безопасно? Если нет, то как мне сделать доступ к dictionary безопасным?

Ответы [ 2 ]

5 голосов
/ 26 февраля 2012

Как сказал UIAdam в своем комментарии, __block здесь ничего не делает для вас; Вы изменяете словарь, а не присваиваете переменную. Переменная будет продолжать указывать на один и тот же словарь навсегда.

На самом деле, __block может на самом деле причинить вам боль, поскольку это означает, что переменная не будет захвачена блоком. Если вы не используете ARC, это означает, что словарь не будет сохранен, и блок может вскоре отправить сообщения мертвому объекту. Я не уверен, случайно ли ARC это меняет. В любом случае вы должны оставить __block вне этой переменной; если ничего другого, код более четко выражает ваши намерения без него.

Что касается вашего реального вопроса о безопасности потоков, этот код не является безопасным. Согласно Сводке по безопасности потоков , классы изменяемой коллекции не являются поточно-ориентированными: вы должны отправлять сообщения в изменяемую коллекцию не более чем из одного потока за раз. Синхронизация будет одним из способов; установка максимального числа одновременных операций в очереди в 1 будет другим.

4 голосов
/ 26 февраля 2012

это не потокобезопасный, но не имеет ничего общего с ключевым словом __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

...