Подтвердить что ты не робот

Почему "атомный" определитель @property по умолчанию в Objective C, когда я нахожу себя неатомным в 100% случаев?

За несколько лет работы в качестве разработчика iOS я не думаю, что когда-либо использовал свойство atomic. Если я вижу потенциальные условия гонки или проблемы с целостностью данных из-за потоковой передачи, использование atom в @property никогда не поможет. Я использую обычные методы безопасности потоков транзакций/единиц работы (используя механизмы блокировок, семафоров или что-то еще).

Кто-нибудь имеет (или знает) какие-либо практические примеры использования atom? (Мне бы хотелось увидеть примеры реальных/практических примеров)

После написания nonatomic, возможно, в миллиардном времени, мне также интересно, почему Apple решила сделать atomic по умолчанию.

4b9b3361

Ответ 1

Что касается первой проблемы, возникшей у вас, возможно, потому что

Хотя "атомный" означает, что доступ к свойству является потокобезопасным, просто создание всех свойств в вашем атоме класса не означает, что ваш класс или, в общем, ваш графический объект, является "потокобезопасным", на уровне индивидуальных методов доступа.

Что касается того, почему яблоко делает его атомарным по умолчанию, я не думаю, что есть веская причина, это было просто плохое дизайнерское решение. Ребята на сессиях WWDC неоднократно призывали людей использовать неатомические средства, где бы вы ни находились, чтобы исключить влияние производительности.

Ответ 2

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

У меня нет никаких доказательств того, что это было причиной решения, но это имеет смысл для меня.

(Если вам интересно, в сборке мусора все еще есть случаи, когда простое назначение неатомное - это происходит, когда значение больше размера слова процесса. На практике это происходит только с structs.)

Изменить: Добавлены источники

Более подробную информацию об атомарности синтезированных свойств в коллекции мусора можно найти в Objective-C Язык программирования → Объявленные свойства → Производительность и потоки, где говорится: "В среде сбора мусора большинство синтезированных методов являются атомарными, не налагая этих накладных расходов". Собственная атомарность упоминается более подробно в сессии WWDC 2008 года 420 "Использование коллекции мусора с помощью Objective-C" около отметки 29 минут.

Ответ 3

В двух словах - безопасность потоков. Большинство приложений, которые мы пишем на регулярной основе, довольно просты и, как таковые, фактически получат выгоду от отсутствия дополнительных блокировок.


От Apple Objective-C Язык программирования:

Свойства по умолчанию являются атомарными, так что синтезированные аксессоры обеспечивают надежный доступ к свойствам в многопоточной среде, то есть значение, возвращаемое из получателя или заданное с помощью установщика, всегда полностью извлекается или устанавливается независимо от того, какие другие потоки выполняя одновременно. Для получения дополнительной информации см. "" Производительность и потоки".

Если вы не укажете неатомический, то в среде с подсчетом ссылок синтезированный get accessor для свойства объекта использует блокировку и сохраняет и автореализует возвращаемое значение - реализация будет похожа на следующее:

[_internal lock]; // lock using an object-level lock
id result = [[value retain] autorelease];
[_internal unlock];
return result;

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

Ответ 4

Когда Apple впервые представила концепцию свойств, был большой аргумент в отношении того, должны ли быть atomic или nonatomic по умолчанию, а атомные люди выиграли.

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

-(MyObj*) someProperty
{
     return someInstVar;
}

Возможно, что какой-то другой поток может освободить объект, на который указывает someInstVar после того, как указатель был помещен в регистр для возврата, но до того, как вызывающий пользователь успел его сохранить. Даже это нехорошо:

-(MyObj*) someProperty
{
     return [[someInstVar retain] autorelease];
}

потому что какой-то другой поток может отключить someInstVar непосредственно перед тем, как счетчик удержания будет увеличен.

Единственный способ безопасного возврата указателя в многопоточную среду - это примерно так:

-(MyObj*) someProperty
{
     @synchronized(self)
     {
         return [[someInstVar retain] autorelease];
     }
}

а также синхронизировать сеттер.

Однако проблема заключается в том, что блокировка очень дорогая (на самом деле они использовали что-то гораздо более легкое, чем @синхронизированное, но все еще дорогое), поэтому все все равно использовали неатомическое выражение, и просто сделать все свойства атома не наделяет нить безопасность в целом, поэтому в любом случае требуются другие методы, и они, как правило, устраняют проблему, о которой я говорил выше.

Есть много людей, которые думают, что было принято неправильное решение о том, что должно быть по умолчанию, но теперь оно не может быть изменено для обратной совместимости. Я нахожу себя набрав nonatomic, даже не задумываясь.

Ответ 5

Атомные вызовы - это вызовы, которые невозможно прервать. Весь вызов должен быть выполнен.

Обновление чего-то вроде общей переменной счетчика будет чем-то, что может быть атомарным, потому что вы не хотите, чтобы два процесса пытались получить доступ к переменной в одно и то же время. Действия должны выполняться "атомарно".

В этом SO-сообщении много полезной информации: Atomic vs nonatomic properties относительно различий и проблем безопасности потоков атома против неатомических.