Ключевое слово 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