Атомные свойства против многопоточности в Objective-C
В большинстве обсуждений, которые я читал, это указывает на то, что создание свойства атомарным не гарантирует его потокобезопасность, оно просто гарантирует, что возвращаемое значение не будет мусором в результате записи одного объекта в него и другого пытаясь прочитать это одновременно.
Я понимаю, что это не потокобезопасно, так как третий объект может писать его, и хотя объект, к которому он обращается, не вернет мусор, не совсем ясно, какое значение он получит, так как несколько объектов записывают в него одновременно время, и он может получить любое их значение.
Поэтому, когда мы говорим, что он не будет возвращать мусор, это будет означать, что если объект не является атомарным и объект пытается получить к нему доступ, когда другой пишет в него, он может получить результат обратно в середине записи, и получить только частичную, неполную версию изменений, вызванных записью? Это то, что означает "мусор" в этом смысле, и какие атомные свойства помогают предотвратить?
5 ответов
atomic
свойство в Objective C гарантирует, что вы никогда не увидите частичные записи. Когда @property
имеет атрибут atomic
невозможно только частично записать значение. Сеттер такой:
- (void)setProp:(NSString *)newValue {
[_prop lock];
_prop = newValue;
[_prop unlock];
}
Таким образом, если два потока хотят записать значение @ "test" и @ "otherTest" одновременно, то в любой момент времени это свойство может быть только начальным значением свойства или @ "test" или @ "otherTest".nonatomic
быстрее, но значение является значением мусора и не содержит частичной строки @"test"/@"otherTest" (thx @Gavin) или любого другого значения мусора.
Но atomic
только потокобезопасен с простым использованием. Это не гарантируется. Аппледок говорит следующее:
Рассмотрим
XYZPerson
объект, в котором имя и фамилия человека изменяются с помощью атомарных методов доступа из одного потока. Если другой поток обращается к обоим именам одновременно, методы атомарного метода получения возвращают полные строки (без сбоев), но нет гарантии, что эти значения будут правильными именами относительно друг друга. Если к изменению обращаются к первому имени, а после изменения - к последнему имени, вы получите непоследовательную, несовпадающую пару имен.
У меня никогда не было проблем с использованием Atomic вообще. Я разработал код таким образом, чтобы не было проблем с атомарными свойствами.
В ответ на ваш третий абзац; по сути да. Атомный номер не может быть прочитан, пока поток записывает номер.
Например, если поток записал первые два байта атомного четырехбайтового числа, и чтение этого числа запрашивается в другом потоке, это чтение должно ждать, пока все четыре байта не будут записаны.
И наоборот, если поток записал первые два байта неатомарного четырехбайтового числа, и в тот момент запрашивается чтение этого числа в другом потоке, он будет читать первые два новых байта данных, но получит старые данные из предыдущей операции записи в двух других байтах.
Ответ Роберта Харви верен, но есть один случай, когда люди считают, что люди часто скучают. Рассмотрим этот код: http://pastebin.com/S7XyJm6G
Помимо предотвращения чтения частично записанных значений, атомарные свойства также препятствуют возвращению объектов, для которых вы не управляете временем жизни (они делают это путем сохранения, а затем автоматического высвобождения объекта). Это важно в однопоточном коде, таком как пример, который я привел, но еще более важно в многопоточном коде, где другой поток может вызвать освобождение объекта из-под вас.
При параллельном программировании:
атомарный означает, что если значение свойства, доступное для операции записи в каком-либо потоке (поток # 1) и другом потоке (поток # 2), пытается получить доступ к атомарному значению для операции чтения или записи, тогда другой поток (поток # 2) ожидает, пока поток # 1 завершает свою задачу. Другими словами, атомарная синхронизация доступа к свойству по принципу "первым пришел - первым обслужен".
неатомарное означает, что при обращении к значению свойства для операции записи в каком-то потоке (поток # 1) и другом потоке (поток # 2) пытается получить доступ к неатомарному значению для операции чтения или записи, тогда другой поток (поток # 2) получает значение сразу получает старое значение
Явная реализация
@property (атомарный, сохранить) NSNumber *count
будет так
- (NSNumber *)count {
NSNumber *count;
@synchronized(self) {
count = [_count retain]; // +1
}
return [count autorelease]; // delayed -1
}
- (void)setCount:(NSNumber *)count {
id oldValue;
@synchronized(self) {
oldValue = _count;
_count = [count retain];
}
[oldValue release];
}
Atomic - поведение по умолчанию для свойства.Atomic свойство добавляет уровень безопасности потока при получении или установке значений. Таким образом, метод получения и установки свойства всегда будет полностью завершен независимо от того, что делают другие потоки. доступ к этим свойствам будет немного медленнее, чем к неатомному эквиваленту.
И явно мы бы реализовать
@property (nonatomic, retain) NSNumber *count
как это
- (NSNumber *)count {
return _count;
}
- (void)setCount:(NSNumber *)count {
if (count != _count) {
id oldValue = _count;
_count = [count retain];
[_oldValue release];
}
}
Неатомарные свойства не являются потокобезопасными и возвращают свои свойства напрямую. Это будет быстрее, чем атомные свойства, но, очевидно, несет некоторый риск, если не будут приняты меры предосторожности.
сеттер и геттер для этих неатомических свойств