Ключевое слово Objective-C __block и безопасность потока

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

Решение

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

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

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

Это не потокобезопасно, но ничего общего с __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

Другие вопросы по тегам