Почему "атомный" определитель @property по умолчанию в Objective C, когда я нахожу себя неатомным в 100% случаев?
За несколько лет работы в качестве разработчика iOS я не думаю, что когда-либо использовал свойство atomic. Если я вижу потенциальные условия гонки или проблемы с целостностью данных из-за потоковой передачи, использование atom в @property никогда не поможет. Я использую обычные методы безопасности потоков транзакций/единиц работы (используя механизмы блокировок, семафоров или что-то еще).
Кто-нибудь имеет (или знает) какие-либо практические примеры использования atom? (Мне бы хотелось увидеть примеры реальных/практических примеров)
После написания nonatomic, возможно, в миллиардном времени, мне также интересно, почему Apple решила сделать atomic по умолчанию.
Ответы
Ответ 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 относительно различий и проблем безопасности потоков атома против неатомических.