Атомные свойства против многопоточности в 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];
    }
}

Неатомарные свойства не являются потокобезопасными и возвращают свои свойства напрямую. Это будет быстрее, чем атомные свойства, но, очевидно, несет некоторый риск, если не будут приняты меры предосторожности.

сеттер и геттер для этих неатомических свойств

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