Вопрос: В чем разница между атомными и неатомическими атрибутами?


Что atomicа также nonatomicозначает объявление собственности?

@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;

В чем разница между этими тремя операционными?


1717


источник


Ответы:


Последние два идентичны; «atomic» - это поведение по умолчанию ( обратите внимание, что это не ключевое слово; он определяется только отсутствием nonatomic- atomicбыло добавлено как ключевое слово в последних версиях llvm / clang).

Предполагая, что вы @synthesizing реализации метода, атомный или неатомный изменяет сгенерированный код. Если вы пишете свой собственный сеттер / получатель, атомарное / неатомическое / сохранение / назначение / копирование являются просто рекомендательными. (Примечание: @synthesize теперь является поведением по умолчанию в последних версиях LLVM. Также нет необходимости объявлять переменные экземпляра, они также будут автоматически синтезированы и будут иметь _добавленные к их имени, чтобы предотвратить случайный прямой доступ).

С «атомарным» синтезированный сеттер / геттер будет обеспечивать, чтобы все значение всегда возвращается из геттера или устанавливается установщиком, независимо от активности сеттера в любом другом потоке. То есть, если поток A находится в середине получателя, а поток B вызывает сеттер, фактическое жизнеспособное значение - объект с автореализацией, скорее всего, - будет возвращен вызывающему абоненту в A.

В nonatomic, такие гарантии не предоставляются. Таким образом, nonatomicзначительно быстрее, чем «атомный».

Что такое «атомный» не сделайте все гарантии безопасности потоков. Если поток A вызывает геттер одновременно с потоком B и C, вызывающим сеттер с разными значениями, поток A может получить любое из трех возвращенных значений - тот, который вызывается, или любые значения, переданные в сеттеры в B и C. Аналогично, объект может в конечном итоге получить значение от B или C, не указывая.

Обеспечение целостности данных - одна из основных задач многопоточного программирования - достигается другими способами.

Добавление к этому:

atomicityодного свойства также не может гарантировать безопасность потока, когда в игре играют несколько зависимых свойств.

Рассматривать:

 @property(atomic, copy) NSString *firstName;
 @property(atomic, copy) NSString *lastName;
 @property(readonly, atomic, copy) NSString *fullName;

В этом случае поток A может быть переименован в объект путем вызова setFirstName:и затем вызывая setLastName:, Тем временем поток B может вызвать fullNameмежду двумя вызовами потока A и получит новое имя в сочетании со старой фамилией.

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


1662



Это объясняется в Apple документация , но ниже приведены некоторые примеры того, что на самом деле происходит. Обратите внимание, что нет «атомного» ключевого слова, если вы не укажете «неатомический», тогда свойство является атомарным, но явно указывать «атомный» приведет к ошибке.

//@property(nonatomic, retain) UITextField *userName;
//Generates roughly

- (UITextField *) userName {
    return userName;
}

- (void) setUserName:(UITextField *)userName_ {
    [userName_ retain];
    [userName release];
    userName = userName_;
}

Теперь атомный вариант немного сложнее:

//@property(retain) UITextField *userName;
//Generates roughly

- (UITextField *) userName {
    UITextField *retval = nil;
    @synchronized(self) {
        retval = [[userName retain] autorelease];
    }
    return retval;
}

- (void) setUserName:(UITextField *)userName_ {
    @synchronized(self) {
      [userName_ retain];
      [userName release];
      userName = userName_;
    }
}

В принципе, атомная версия должна блокировать, чтобы гарантировать безопасность потока, а также набрасывает количество ссылок на объект (и подсчет автоопределения, чтобы сбалансировать его), чтобы объект гарантированно существовал для вызывающего абонента, в противном случае является потенциальным условием гонки, если другой поток устанавливает значение, заставляя отсчет числа ref равным 0.

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


341



атомное

  • это поведение по умолчанию
  • будет гарантировать, что текущий процесс будет завершен ЦП, прежде чем другой процесс обратится к переменной
  • не быстро, так как это гарантирует, что процесс полностью завершен

Неатомарный

  • НЕ является поведением по умолчанию
  • быстрее (для синтезированного кода, то есть для переменных, созданных с использованием @property и @synthesize)
  • небезопасный
  • может привести к неожиданному поведению, когда два разных процесса доступа к одной и той же переменной в одно и то же время

147



Лучший способ понять разницу - использовать следующий пример.

Предположим, что существует свойство атомной строки, называемое «имя», и если вы вызываете [self setName:@"A"]из потока A, вызов [self setName:@"B"]из потока B и вызова [self name]из нити C, то все операции над разными потоками будут выполняться серийно, что означает, что если один поток выполняет сеттер или getter, то другие потоки будут ждать.

Это делает свойство «имя» безопасным для чтения / записи, но если другой поток, D, вызывает [name release]одновременно эта операция может привести к сбою, потому что здесь нет вызова setter / getter. Это означает, что объект безопасен для чтения / записи (ATOMIC), но не является потокобезопасным, поскольку другие потоки могут одновременно отправлять сообщения любого типа в объект. Разработчик должен обеспечить безопасность потоков для таких объектов.

Если свойство «name» было неатомным, то все потоки в приведенном выше примере - A, B, C и D будут выполняться одновременно с получением любого непредсказуемого результата. В случае атома сначала выполняется один из A, B или C, но D может выполняться параллельно.


124



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

Какова функциональная разница между этими 3?

Я всегда считал атомным по умолчанию довольно любопытным. На уровне абстракции мы работаем, используя атомные свойства для класса в качестве транспортного средства для достижения 100% -ной защиты от потока. Для действительно правильных многопоточных программ вмешательство программиста почти наверняка является обязательным требованием. Между тем характеристики и исполнение производительности еще не были детально изучены. На протяжении многих лет, написав несколько многопоточных программ, я объявлял свои свойства как nonatomicвсе время, потому что атомный не был разумным для каких-либо целей. При обсуждении деталей атомных и неатомических свойств этот вопрос , Я сделал некоторое профилирование, столкнувшись с некоторыми любопытными результатами.

выполнение

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

Другое отличие состоит в том, что атомарные свойства будут удерживать / освобождать цикл ваших объектов внутри геттера.

Представление

Вот интересная часть: производительность с использованием доступа к атомной собственности в неоспоримый (например, однопоточные) случаи могут быть очень быстрыми в некоторых случаях. В менее идеальных случаях использование атомных доступов может стоить более 20 раз над накладными расходами nonatomic, В то время Оспариваемые case с использованием 7 потоков был в 44 раза медленнее для трехбайтовой структуры (2,2 ГГц Core i7 Quad Core, x86_64). Трехбайтовая структура является примером очень медленного свойства.

Интересное примечание: пользовательские аксессоры трехбайтовой структуры были в 52 раза быстрее, чем синтезированные атомарные аксессоры; или 84% - скорость синтезированных неатомических аксессуаров.

Объекты в оспариваемых случаях также могут превышать 50 раз.

Из-за количества оптимизаций и вариаций в реализациях довольно сложно измерить влияние реального мира в этих контекстах. Вы часто можете услышать что-то вроде «Доверяйте ему, если вы не профиль и не найдете, что это проблема». Из-за уровня абстракции на самом деле довольно сложно измерить фактическое воздействие. Исчезновение фактических затрат из профилей может быть очень трудоемким, а из-за абстракций довольно неточным. Кроме того, ARC против MRC может иметь большое значение.

Итак, давайте отступим, не сосредоточив внимание на реализации доступа к ресурсам, мы включим обычных подозреваемых, таких как objc_msgSend, и изучите некоторые реальные результаты высокого уровня для многих вызовов NSStringгеттер в неоспоримый случаи (значения в секундах):

  • MRC | неатомный | вручную реализованные геттеры: 2
  • MRC | неатомный | синтезированный геттер: 7
  • MRC | атомный | синтезированный геттер: 47
  • ARC | неатомный | синтезированный геттер: 38 (обратите внимание: ARC добавляет циферблат ссылок здесь)
  • ARC | атомный | синтезированный геттер: 47

Как вы, наверное, догадались, активность счетчика / цикличность значительного вклада в атомику и под ARC. Вы также увидите большие различия в оспариваемых случаях.

Хотя я уделяю пристальное внимание производительности, я все же говорю Сначала семантика! , Между тем, производительность является низким приоритетом для многих проектов. Однако, зная подробности исполнения и стоимость технологий, которые вы используете, конечно, не повредит. Вы должны использовать правильную технологию для своих нужд, целей и способностей. Надеемся, это сэкономит вам несколько часов сравнений и поможет вам принять более обоснованное решение при разработке ваших программ.


108



Atomic = thread safety

Non-atomic = No thread safety

Thread safety:

Instance variables are thread-safe if they behave correctly when accessed from multiple threads, regardless of the scheduling or interleaving of the execution of those threads by the runtime environment, and with no additional synchronization or other coordination on the part of the calling code.

In our context:

If a thread changes the value of the instance the changed value is available to all the threads, and only one thread can change the value at a time.

Where to use atomic:

if the instance variable is gonna be accessed in a multithreaded environment.

Implication of atomic:

Not as fast as nonatomic because nonatomic doesn't require any watchdog work on that from runtime .

Where to use nonatomic:

If the instance variable is not gonna be changed by multiple threads you can use it. It improves the performance.


88



I found a pretty well put explanation of atomic and non-atomic properties here. Here's some relevant text from the same:

'atomic' means it cannot be broken down. In OS/programming terms an atomic function call is one that cannot be interrupted - the entire function must be executed, and not swapped out of the CPU by the OS's usual context switching until it's complete. Just in case you didn't know: since the CPU can only do one thing at a time, the OS rotates access to the CPU to all running processes in little time-slices, to give the illusion of multitasking. The CPU scheduler can (and does) interrupt a process at any point in its execution - even in mid function call. So for actions like updating shared counter variables where two processes could try to update the variable at the same time, they must be executed 'atomically', i.e., each update action has to finish in its entirety before any other process can be swapped onto the CPU.

So I'd be guessing that atomic in this case means the attribute reader methods cannot be interrupted - in effect meaning that the variable(s) being read by the method cannot change their value half way through because some other thread/call/function gets swapped onto the CPU.

Because the atomic variables can not be interrupted, the value contained by them at any point is (thread-lock) guaranteed to be uncorrupted, although, ensuring this thread lock makes access to them slower. non-atomic variables, on the other hand, make no such guarantee but do offer the luxury of quicker access. To sum it up, go with non-atomic when you know your variables won't be accessed by multiple threads simultaneously and speed things up.


67



After reading so many articles, Stack Overflow posts and making demo applications to check variable property attributes, I decided to put all the attributes information together:

  1. atomic // Default
  2. nonatomic
  3. strong = retain // Default
  4. weak = unsafe_unretained
  5. retain
  6. assign // Default
  7. unsafe_unretained
  8. copy
  9. readonly
  10. readwrite // Default

In the article Variable property attributes or modifiers in iOS you can find all the above-mentioned attributes, and that will definitely help you.

  1. atomic

    • atomic means only one thread access the variable (static type).
    • atomic is thread safe.
    • But it is slow in performance
    • atomic is the default behavior
    • Atomic accessors in a non garbage collected environment (i.e. when using retain/release/autorelease) will use a lock to ensure that another thread doesn't interfere with the correct setting/getting of the value.
    • It is not actually a keyword.

    Example:

        @property (retain) NSString *name;
    
        @synthesize name;
    
  2. nonatomic

    • nonatomic means multiple thread access the variable (dynamic type).
    • nonatomic is thread-unsafe.
    • But it is fast in performance
    • nonatomic is NOT default behavior. We need to add the nonatomic keyword in the property attribute.
    • It may result in unexpected behavior, when two different process (threads) access the same variable at the same time.

    Example:

        @property (nonatomic, retain) NSString *name;
    
        @synthesize name;
    

61



Easiest answer first: There's no difference between your second two examples. By default, property accessors are atomic.

Atomic accessors in a non garbage collected environment (i.e. when using retain/release/autorelease) will use a lock to ensure that another thread doesn't interfere with the correct setting/getting of the value.

See the "Performance and Threading" section of Apple's Objective-C 2.0 documentation for some more information and for other considerations when creating multi-threaded apps.


52



Atomic :

Atomic guarantees that access to the property will be performed in an atomic manner. E.g. it always return a fully initialised objects, any get/set of a property on one thread must complete before another can access it.

If you imagine the following function occurring on two threads at once you can see why the results would not be pretty.

-(void) setName:(NSString*)string
{
  if (name)
  {
    [name release]; 
    // what happens if the second thread jumps in now !?
    // name may be deleted, but our 'name' variable is still set!
    name = nil;
  }

  ...
}

Pros : Return of fully initialised objects each time makes it best choice in case of multi-threading.

Cons : Performance hit, makes execution a little slower

Non-Atomic :

Unlike Atomic, it doesn't ensure fully initialised object return each time.

Pros : Extremely fast execution.

Cons : Chances of garbage value in case of multi-threading.


51



Atomic means only one thread accesses the variable (static type). Atomic is thread-safe, but it is slow.

Nonatomic means multiple threads access the variable (dynamic type). Nonatomic is thread-unsafe, but it is fast.


31



Atomic is thread safe, it is slow and it well-assures (not guaranteed) that only the locked value is provided no matter how many threads are attempting access over the same zone. When using atomic, a piece of code written inside this function becomes the part of the critical section, to which only one thread can execute at a time.

It only assures the thread safety; it does not guarantee that. What I mean is you hire an expert driver for you car, still it doesn't guarantees car won't meet an accident. However, probability remains the slightest.

Atomic - it can't be broken down, so the result is expected. With nonatomic - when another thread access the memory zone it can modify it, so the result is unexpected.

Code Talk :

Atomic make getter and setter of the property thread safe. for example if u have written :

self.myProperty = value;

is thread safe.

[myArray addObject:@"Abc"] 

is NOT thread safe.


14