Jaka jest różnica między atrybutami atomowymi i nieatomowymi?


Odpowiedzi:


1761

Dwa ostatnie są identyczne; „atomowy” jest domyślnym zachowaniem ( zwróć uwagę, że tak naprawdę nie jest słowem kluczowym; jest określone tylko przez braknonatomic - atomiczostał dodany jako słowo kluczowe w najnowszych wersjach llvm / clang).

Zakładając, że @syntetyzujesz implementacje metod, atomowa vs. nieatomowa zmienia generowany kod. Jeśli piszesz własny setter / getters, atomowe / nieatomowe / zachowaj / przypisuj / kopiuj są jedynie wskazówkami. (Uwaga: @synthesize jest teraz domyślnym zachowaniem w najnowszych wersjach LLVM. Nie ma również potrzeby deklarowania zmiennych instancji; zostaną one również zsyntetyzowane automatycznie i będą _poprzedzone swoją nazwą, aby zapobiec przypadkowemu bezpośredniemu dostępowi).

W przypadku „atomowej” zsyntetyzowany setter / getter zapewnia, że cała wartość jest zawsze zwracana z gettera lub ustawiana przez setter, niezależnie od aktywności setera w jakimkolwiek innym wątku. Oznacza to, że jeśli wątek A znajduje się w środku modułu pobierającego, podczas gdy wątek B wywołuje funkcję ustawiającą, rzeczywista wartość rzeczywista - obiekt automatycznie wydany, najprawdopodobniej - zostanie zwrócony do obiektu wywołującego w A.

W nonatomicnie udziela się takich gwarancji. Jest więc nonatomicznacznie szybszy niż „atomowy”.

To, czego nie robi „atom”, nie daje żadnych gwarancji bezpieczeństwa nici. Jeśli wątek A wywołuje getter jednocześnie z wątkiem B i C wywołującym setter z różnymi wartościami, wątek A może otrzymać jedną z trzech wartości - tę przed wywołaniem dowolnego settera lub jedną z wartości przekazanych do setterów w B i C. Podobnie, obiekt może otrzymać wartość z B lub C, co nie jest w stanie powiedzieć.

Zapewnienie integralności danych - jednego z głównych wyzwań programowania wielowątkowego - osiąga się innymi sposobami.

Dodając do tego:

atomicity pojedynczej właściwości nie może również zagwarantować bezpieczeństwa wątku, gdy w grę wchodzi wiele zależnych właściwości.

Rozważać:

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

W takim przypadku wątek A może zmienić nazwę obiektu przez wywołanie, setFirstName:a następnie wywołanie setLastName:. W międzyczasie wątek B może wywoływać fullNamemiędzy dwoma wywołaniami wątku A i otrzyma nowe imię w połączeniu ze starym nazwiskiem.

Aby rozwiązać ten problem, potrzebujesz modelu transakcyjnego . To znaczy jakiś inny rodzaj synchronizacji i / lub wykluczenia, który pozwala wykluczyć dostęp fullNamepodczas aktualizacji właściwości zależnych.


21
Biorąc pod uwagę, że każdy kod zabezpieczający wątki będzie robił swoje własne blokowanie itp., Kiedy chciałbyś użyć atomowych akcesorów własności? Mam problem z wymyśleniem dobrego przykładu.
Daniel Dickison

8
@bbum Ma sens. Podoba mi się twój komentarz do innej odpowiedzi, że bezpieczeństwo wątków jest bardziej problemem na poziomie modelu. Z definicji bezpieczeństwa wątków IBM: ibm.co/yTEbjY "Jeśli klasa jest poprawnie zaimplementowana, co jest innym sposobem stwierdzenia, że ​​jest zgodna ze specyfikacją, brak sekwencji operacji (odczytuje lub zapisuje pola publiczne i wywołuje metody publiczne) na obiektach tej klasy powinno być w stanie doprowadzić obiekt do nieprawidłowego stanu, zaobserwować, że obiekt znajduje się w niewłaściwym stanie lub naruszyć dowolne niezmienniki, warunki wstępne lub dodatkowe klasy. ”
Ben Flynn

6
Oto przykład podobny do @StevenKramer: Mam @property NSArray* astronomicalEvents;listę, która wyświetla dane, które chcę wyświetlić w interfejsie użytkownika. Gdy aplikacja uruchamia wskaźnik wskazuje pustą tablicę, aplikacja pobiera dane z Internetu. Po zakończeniu żądania WWW (w innym wątku) aplikacja buduje nową tablicę, a następnie atomowo ustawia właściwość na nową wartość wskaźnika. Jest bezpieczny dla wątków i nie musiałem pisać kodu blokującego, chyba że coś mi brakuje. Wydaje mi się bardzo przydatny.
bugloaf

10
@HotLicks Kolejna fajna; na niektórych architekturach (nie pamiętam, która), 64-bitowe wartości przekazane jako argument mogą być przekazane w połowie w rejestrze, a w połowie na stosie. atomiczapobiega odczytom połowy wartości wątku poprzecznego. (To był fajny błąd do wyśledzenia.)
bbum

8
@congliu Wątek A zwraca obiekt bez retain/autoreleasetańca. Wątek B zwalnia obiekt. Wątek A rozkwita . atomiczapewnia, że ​​wątek A ma silne odniesienie (wartość zatrzymania +1) dla wartości zwracanej.
bbum

360

Wyjaśnia to dokumentacja Apple , ale poniżej znajdują się przykłady tego, co się faktycznie dzieje.

Zauważ, że nie ma słowa kluczowego „atomowy”, jeśli nie określisz „nieatomowy”, wówczas właściwość jest atomowa, ale jawne określenie „atomowy” spowoduje błąd.

Jeśli nie określisz „nonatomic”, wówczas właściwość jest atomowa, ale nadal możesz jawnie określić „atomowy” w najnowszych wersjach, jeśli chcesz.

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

- (UITextField *) userName {
    return userName;
}

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

Teraz wariant atomowy jest nieco bardziej skomplikowany:

//@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_;
    }
}

Zasadniczo wersja atomowa musi wziąć blokadę, aby zagwarantować bezpieczeństwo wątku, a także zwiększa liczbę referencji na obiekcie (i liczbę automatycznych wydań, aby go zrównoważyć), aby zagwarantować istnienie obiektu dla wywołującego, w przeciwnym razie jest potencjalnym stanem wyścigu, jeśli inny wątek ustawia wartość, powodując spadek liczby referencji do 0.

W rzeczywistości istnieje wiele różnych wariantów tego, jak te rzeczy działają, w zależności od tego, czy właściwości są wartościami skalarnymi, czy obiektami oraz od tego, jak zachowują, kopiują, tylko do odczytu, nieatomowe itp. Ogólnie rzecz biorąc, syntezatory właściwości po prostu wiedzą, jak zrobić „właściwą rzecz” dla wszystkich kombinacji.


8
@Louis Gerbarg: Wierzę swoją wersję (nonatomic, zachowują) seter nie będzie działać prawidłowo, jeśli starają się przypisać ten sam obiekt (czyli: Nazwa == userName_)
Florin

5
Twój kod jest nieco mylący; nie ma żadnej gwarancji na to, które urządzenia pobierające / ustawiające atom są zsynchronizowane. Krytycznie @property (assign) id delegate;nie jest zsynchronizowany na niczym (iOS SDK GCC 4.2 ARM -Os), co oznacza, że ​​istnieje wyścig pomiędzy [self.delegate delegateMethod:self];i foo.delegate = nil; self.foo = nil; [super dealloc];. Zobacz stackoverflow.com/questions/917884/…
tc.

@fyolnish Nie jestem pewien, co _val/ valsą, ale nie, nie bardzo. Moduł pobierający dla atomu copy/ retainwłaściwości musi upewnić się, że nie zwróci obiektu, którego licznik staje się zerowy, ponieważ setter jest wywoływany w innym wątku, co zasadniczo oznacza, że ​​musi odczytać ivar, zachować go, jednocześnie upewniając się, że setter nie nadpisał i wydał go, a następnie automatycznie wydał, aby zrównoważyć zatrzymanie. Zasadniczo oznacza to, że zarówno moduł pobierający, jak i ustawiający musi używać blokady (jeśli układ pamięci został naprawiony, powinno to być wykonalne za pomocą instrukcji CAS2; niestety -retainjest to wywołanie metody).
tc.

@tc Minęło sporo czasu, ale to, co chciałem napisać, to prawdopodobnie: gist.github.com/fjolnir/5d96b3272c6255f6baae Ale tak, możliwe jest, że stara wartość zostanie odczytana przez czytelnika przed setFoo: zwraca i wydana przed czytnik zwraca. Ale może gdyby setter użył opcji -autorelease zamiast -release, to by to naprawiło.
Fjölnir,

@fyolnish Niestety nie: Ta automatyczna publikacja w wątku setera, podczas gdy trzeba ją automatycznie wydać w wątku gettera. Wygląda również na to, że istnieje (niewielka) szansa na wyczerpanie stosu, ponieważ używasz rekurencji.
tc.

169

Atomowy

  • jest domyślnym zachowaniem
  • upewni się, że proces zostanie zakończony przez CPU, zanim inny proces uzyska dostęp do zmiennej
  • nie jest szybki, ponieważ zapewnia całkowite zakończenie procesu

Bezatomowy

  • NIE jest zachowaniem domyślnym
  • szybciej (dla kodu zsyntetyzowanego, to znaczy dla zmiennych utworzonych za pomocą @property i @synthesize)
  • nie jest bezpieczny dla wątków
  • może powodować nieoczekiwane zachowanie, gdy dwa różne procesy uzyskują dostęp do tej samej zmiennej w tym samym czasie

137

Najlepszym sposobem na zrozumienie różnicy jest użycie następującego przykładu.

Załóżmy, że istnieje właściwość ciągu atomowego o nazwie „nazwa”, a jeśli wywołujesz [self setName:@"A"]z wątku A, wywołujesz [self setName:@"B"]z wątku B i wywołujesz [self name]z wątku C, wówczas wszystkie operacje na różnych wątkach będą wykonywane szeregowo, co oznacza, że ​​jeśli jeden wątek wykonuje setter lub getter, wtedy inne wątki będą czekać.

To sprawia, że ​​właściwość „nazwa” odczytuje / zapisuje bezpiecznie, ale jeśli inny wątek, D, wywołuje [name release]jednocześnie, to ta operacja może spowodować awarię, ponieważ nie jest tu zaangażowane wywołanie setter / getter. Co oznacza, że ​​obiekt jest bezpieczny do odczytu / zapisu (ATOMIC), ale nie jest bezpieczny dla wątków, ponieważ inne wątki mogą jednocześnie wysyłać do obiektu wiadomości dowolnego typu. Deweloper powinien zapewnić bezpieczeństwo wątków dla takich obiektów.

Jeśli właściwość „name” była nieatomowa, wówczas wszystkie wątki w powyższym przykładzie - A, B, C i D wykonają się jednocześnie, dając dowolny nieprzewidywalny wynik. W przypadku atomu, jeden z A, B lub C wykona się jako pierwszy, ale D może nadal wykonać równolegle.


116

Składnia i semantyka są już dobrze zdefiniowane przez inne doskonałe odpowiedzi na to pytanie. Ponieważ wykonanie i wydajność nie są szczegółowo opisane, dodam swoją odpowiedź.

Jaka jest funkcjonalna różnica między tymi 3?

Zawsze uważałem atom za domyślny dość ciekawy. Na poziomie abstrakcji, nad którym pracujemy, wykorzystanie właściwości atomowych dla klasy jako pojazdu w celu osiągnięcia 100% bezpieczeństwa wątków jest bardzo ważne. W przypadku naprawdę poprawnych programów wielowątkowych interwencja programisty jest prawie na pewno wymogiem. Tymczasem charakterystyki wydajności i wykonanie nie zostały jeszcze szczegółowo opisane. Przez lata pisząc kilka programów wielowątkowych, nonatomiccały czas deklarowałem swoje właściwości, ponieważ atom nie był sensowny w żadnym celu. Podczas dyskusji o szczegółach właściwości atomowych i nieatomowych to pytanie spowodowało, że pewne profilowanie napotkało ciekawe wyniki.

Wykonanie

Ok. Pierwszą rzeczą, którą chciałbym wyjaśnić, jest to, że implementacja blokująca jest zdefiniowana i abstrakcyjna. Louis używa @synchronized(self)tego przykładu - widziałem to jako powszechne źródło zamieszania. Implementacja tak naprawdę nie korzysta @synchronized(self); używa blokad spinowych na poziomie obiektu . Ilustracja Louisa jest dobra na ilustrację wysokiego poziomu używającą konstruktów, które wszyscy znamy, ale ważne jest, aby wiedzieć, że nie używa @synchronized(self).

Kolejna różnica polega na tym, że właściwości atomowe będą zachowywać / zwalniać cykl obiektów w getterze.

Wydajność

Oto interesująca część: Wydajność wykorzystująca dostęp do właściwości atomowych w przypadkach bezspornych (np. Jednowątkowych) może być naprawdę bardzo szybka w niektórych przypadkach. W mniej niż idealnych przypadkach korzystanie z dostępu atomowego może kosztować ponad 20 razy więcej nonatomic. Podczas gdy sporna sprawa wykorzystująca 7 wątków była 44 razy wolniejsza dla trzy-bajtowej struktury (2,2 GHz Core i7 Quad Core, x86_64). Trzy bajtowa struktura jest przykładem bardzo wolnej właściwości.

Interesująca uwaga dodatkowa: zdefiniowane przez użytkownika akcesoria trzy bajtowej struktury były 52 razy szybsze niż zsyntetyzowane akcesoria atomowe; lub 84% prędkości zsyntetyzowanych nieatomowych akcesoriów.

Przedmioty w spornych przypadkach mogą również przekroczyć 50 razy.

Ze względu na liczbę optymalizacji i odmian we wdrożeniach trudno jest zmierzyć rzeczywiste wpływy w tych kontekstach. Często możesz usłyszeć coś takiego: „Zaufaj, chyba że profilujesz i uważasz, że to problem”. Ze względu na poziom abstrakcji trudno jest zmierzyć rzeczywisty wpływ. Oczyszczanie rzeczywistych kosztów z profili może być bardzo czasochłonne, a ze względu na abstrakcje dość niedokładne. Również ARC vs MRC może mieć duże znaczenie.

Cofnijmy się więc, nie skupiając się na implementacji dostępu do nieruchomości, uwzględnimy zwykłych podejrzanych, takich jak objc_msgSend, i zbadamy niektóre rzeczywiste wyniki wysokiego poziomu dla wielu wywołań NSStringgettera w przypadkach bezspornych (wartości w sekundach):

  • MRC | nieatomowy | ręcznie zaimplementowane moduły pobierające: 2
  • MRC | nieatomowy | syntezator getter: 7
  • MRC | atomowy | syntezator getter: 47
  • ARC | nieatomowy | syntezator getter: 38 (uwaga: dodawanie ARC do liczby cykli tutaj)
  • ARC | atomowy | syntezator getter: 47

Jak zapewne się domyślacie, aktywność / cykl liczenia referencji ma znaczący wkład w atomikę i pod ARC. Widać też większe różnice w spornych sprawach.

Chociaż zwracam szczególną uwagę na wydajność, nadal mówię, że Semantics First! . Tymczasem wydajność ma niski priorytet w wielu projektach. Jednak znajomość szczegółów wykonania i kosztów używanych technologii z pewnością nie zaszkodzi. Powinieneś używać technologii odpowiedniej do swoich potrzeb, celów i umiejętności. Mamy nadzieję, że pozwoli to zaoszczędzić kilka godzin porównań i pomoże w podejmowaniu lepszych decyzji przy projektowaniu programów.


MRC | atomowy | syntezator getter: 47 ARC | atomowy | syntezator getter: 47 Co sprawia, że ​​są takie same? Czy ARC nie powinno mieć więcej kosztów ogólnych?
SDEZero

2
Więc jeśli właściwości atomowe są złe, to są one domyślne. Aby zwiększyć kod płyty grzewczej?
Kunal Balani,

@ LearnCocos2D właśnie przetestowałem na 10.8.5 na tej samej maszynie, celując w 10,8, dla pojedynczego wątku bezspornego z NSStringnieśmiertelnym: -ARC atomic (BASELINE): 100% -ARC nonatomic, synthesised: 94% -ARC nonatomic, user defined: 86% -MRC nonatomic, user defined: 5% -MRC nonatomic, synthesised: 19% -MRC atomic: 102%- wyniki są dzisiaj trochę inne. Nie robiłem żadnych @synchronizedporównań. @synchronizedjest semantycznie inny i nie uważam tego za dobre narzędzie, jeśli masz nieprofesjonalne programy współbieżne. jeśli potrzebujesz prędkości, unikaj @synchronized.
justin

czy masz gdzieś ten test online? Nadal
dodaję

@ LearnCocos2D, nie przygotowałem ich do spożycia przez ludzi, przepraszam.
justin

95

Atomic = bezpieczeństwo wątku

Bezatomowy = Brak bezpieczeństwa wątku

Bezpieczeństwo wątku:

Zmienne instancji są bezpieczne dla wątków, jeśli zachowują się poprawnie przy dostępie z wielu wątków, niezależnie od planowania lub przeplatania wykonywania tych wątków przez środowisko wykonawcze i bez dodatkowej synchronizacji lub innej koordynacji ze strony kodu wywołującego.

W naszym kontekście:

Jeśli wątek zmienia wartość instancji, zmieniona wartość jest dostępna dla wszystkich wątków i tylko jeden wątek może zmieniać tę wartość naraz.

Gdzie używać atomic:

jeśli zmienna instancji będzie dostępna w środowisku wielowątkowym.

Znaczenie atomic:

Nie tak szybko, ponieważ nonatomicponieważ nonatomicnie wymaga żadnej pracy watchdoga od środowiska uruchomieniowego.

Gdzie używać nonatomic:

Jeśli zmienna instancji nie zostanie zmieniona przez wiele wątków, możesz jej użyć. Poprawia wydajność.


3
Wszystko, co tu powiesz, jest poprawne, ale ostatnie zdanie jest zasadniczo „złe”, Dura, do dzisiejszego programowania. To naprawdę nie do pomyślenia, że ​​w ten sposób próbowałbyś „poprawić wydajność”. (Mam na myśli, że zanim osiągniesz ten wiek, to „nie użyjesz ARC”, „nie użyjesz NSString, ponieważ jest on powolny!” Itd.). Dla ekstremalnego przykładu byłoby to jak powiedzenie „team, nie umieszczaj żadnych komentarzy w kodzie, ponieważ spowalnia nas ”. Nie ma realistycznego potoku rozwoju, w którym chciałbyś (nieistniejący) teoretyczny wzrost wydajności ze względu na zawodność.
Fattie

3
@JoeBlow jest faktem, że możesz to sprawdzić tutaj developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
Durai Amuthan.H

1
Durai, FWIW, ten link bezpośrednio przeczy Twojej tezie „Atomic = bezpieczeństwo wątków”. W dokumencie Apple wyraźnie mówi: „Atomowość własności nie jest synonimem bezpieczeństwa wątku obiektu”. W praktyce atomowa rzadko wystarcza do osiągnięcia bezpieczeństwa nici.
Rob

69

Znalazłem całkiem dobrze umieścić wyjaśnienie właściwości atomowych i non-atomowych tutaj . Oto odpowiedni tekst z tego samego:

„atomowy” oznacza, że ​​nie można go rozbić. W terminologii OS / programowania wywołanie funkcji atomowej to takie, którego nie można przerwać - cała funkcja musi zostać wykonana, a nie zamieniona z procesora przez zwykłe przełączanie kontekstu systemu operacyjnego, dopóki nie zostanie zakończona. Na wypadek, gdybyś nie wiedział: ponieważ procesor może wykonywać tylko jedną rzecz naraz, system operacyjny zmienia dostęp do procesora do wszystkich uruchomionych procesów w krótkich przedziałach czasu, aby zapewnić złudzeniewielozadaniowość. Program planujący procesor może (i rzeczywiście) przerywa proces w dowolnym momencie jego wykonywania - nawet w połowie wywołania funkcji. Tak więc w przypadku akcji takich jak aktualizacja współdzielonych zmiennych licznika, w których dwa procesy mogą próbować zaktualizować zmienną w tym samym czasie, muszą być one wykonane „atomowo”, tj.

Zgaduję więc, że atomowa w tym przypadku oznacza, że ​​metody czytnika atrybutów nie mogą zostać przerwane - w efekcie oznacza to, że zmienne odczytane przez metodę nie mogą zmienić swojej wartości w połowie, ponieważ dostaje się inny wątek / wywołanie / funkcję zamieniono na procesor.

Ponieważ atomiczmienne nie może zostać przerwana, wartości zawarte w nich w każdym momencie jest (gwint blokowaniu) gwarancją nieuszkodzone , chociaż zapewnia tę blokadę gwintu utrudnia dostęp do nich wolniej. non-atomicz drugiej strony zmienne nie dają takiej gwarancji, ale oferują luksus szybszego dostępu. Podsumowując, idź z, non-atomicgdy wiesz, że do twoich zmiennych nie będzie można uzyskać dostępu przez wiele wątków jednocześnie i przyspieszyć.


1
Link jest zepsuty. ; (
Rob

Taki jest problem z linkami :( na szczęście zacytowałem odpowiedni tekst w mojej odpowiedzi
tipycalFlow

67

Po przeczytaniu tylu artykułów, wpisów o przepełnieniu stosu i tworzeniu aplikacji demonstracyjnych do sprawdzania atrybutów właściwości zmiennych, postanowiłem zebrać wszystkie informacje o atrybutach razem:

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

W artykule Zmienne atrybuty właściwości lub modyfikatory w iOS można znaleźć wszystkie wyżej wymienione atrybuty, a to zdecydowanie pomoże.

  1. atomic

    • atomic oznacza, że ​​tylko jeden wątek uzyskuje dostęp do zmiennej (typ statyczny).
    • atomic jest bezpieczny dla wątków.
    • Ale działa wolno
    • atomic jest domyślnym zachowaniem
    • Akcesorium atomowe w środowisku bez odśmiecania (tj. Podczas używania zachowaj / zwolnij / autorelease) użyje blokady, aby upewnić się, że inny wątek nie zakłóci prawidłowego ustawienia / pobrania wartości.
    • To nie jest właściwie słowo kluczowe.

    Przykład:

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

    • nonatomic oznacza dostęp do wielu wątków do zmiennej (typ dynamiczny).
    • nonatomic jest niebezpieczny dla wątków.
    • Ale działa szybko
    • nonatomicNIE jest zachowaniem domyślnym. Musimy dodać nonatomicsłowo kluczowe w atrybucie właściwości.
    • Może to spowodować nieoczekiwane zachowanie, gdy dwa różne procesy (wątki) uzyskują dostęp do tej samej zmiennej w tym samym czasie.

    Przykład:

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

W jaki sposób przypisanie i silne / zachowanie mogą być domyślne?
BangOperator,

strong pochodzi z ARC, zachowanie było domyślne przed ARC
abdullahselek

56

Atomowy:

Atomic gwarantuje, że dostęp do nieruchomości zostanie przeprowadzony w sposób atomowy. Np. Zawsze zwraca w pełni zainicjowane obiekty, każde pobranie / zestaw właściwości w jednym wątku musi się zakończyć, zanim inny będzie mógł uzyskać do niego dostęp.

Jeśli wyobrażasz sobie następującą funkcję występującą jednocześnie w dwóch wątkach, możesz zobaczyć, dlaczego wyniki nie byłyby ładne.

-(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;
  }

  ...
}

Zalety: Zwrócenie w pełni zainicjowanych obiektów za każdym razem czyni najlepszy wybór w przypadku wielowątkowości.

Minusy: Uderzenie wydajności, sprawia, że ​​wykonanie jest nieco wolniejsze

Bezatomowe:

W przeciwieństwie do Atomic, nie zapewnia on w pełni zainicjowanego zwrotu obiektu za każdym razem.

Plusy: wyjątkowo szybkie wykonanie.

Minusy: Szanse na wartość śmieci w przypadku wielowątkowości.


5
Ten komentarz nie ma większego sensu. Możesz wyjaśnić? Jeśli spojrzysz na przykłady w witrynie Apple, to atomowe słowo kluczowe synchronizuje obiekt podczas aktualizacji jego właściwości.
Andrew Grant

52

Najłatwiejsza odpowiedź na początek: nie ma różnicy między twoimi drugimi dwoma przykładami. Domyślnie akcesoria własności są atomowe.

Akcesorium atomowe w środowisku bez odśmiecania (tj. Podczas używania zachowaj / zwolnij / autorelease) użyje blokady, aby upewnić się, że inny wątek nie zakłóci prawidłowego ustawienia / pobrania wartości.

Zobacz sekcję „ Wydajność i wątkowanie ” w dokumentacji Apple Objective-C 2.0, aby uzyskać więcej informacji i inne uwagi podczas tworzenia aplikacji wielowątkowych.


8
Dwa powody. Po pierwsze, kod zsyntetyzowany generuje szybciej (ale nie kod wątkowo bezpieczny). Po drugie, jeśli piszesz akcesory klienckie, które nie są atomowe, pozwala to adnotacji dla każdego przyszłego użytkownika, że ​​kod nie jest atomowy podczas czytania jego interfejsu, bez konieczności ich implementacji.
Louis Gerbarg,


31

Atom oznacza, że ​​tylko jeden wątek uzyskuje dostęp do zmiennej (typ statyczny). Atomic jest bezpieczny dla wątków, ale działa wolno.

Nonatomic oznacza, że ​​wiele wątków ma dostęp do zmiennej (typ dynamiczny). Nonatomic jest niebezpieczny dla nici, ale jest szybki.


14

Atomic jest bezpieczny dla wątków , jest wolny i zapewnia (nie jest gwarantowany) że podana jest tylko wartość zablokowana, bez względu na liczbę wątków próbujących uzyskać dostęp do tej samej strefy. Gdy używasz atomu, fragment kodu zapisany w tej funkcji staje się częścią sekcji krytycznej, do której jednocześnie może być wykonywany tylko jeden wątek.

Zapewnia to jedynie bezpieczeństwo wątku; nie gwarantuje tego.Mam na myśli to, że wynajmujesz kierowcę dla swojego samochodu, ale to nie gwarantuje, że samochód nie spotka wypadku. Jednak prawdopodobieństwo pozostaje najmniejsze.

Atomowy - nie można go rozbić, więc oczekuje się wyniku. Z nonatomic - gdy inny wątek uzyskuje dostęp do strefy pamięci, może ją zmodyfikować, więc wynik jest nieoczekiwany.

Kod rozmowy:

Atomic sprawia, że ​​getter i setter właściwości są bezpieczne. na przykład, jeśli napisałeś:

self.myProperty = value;

jest bezpieczny dla wątków.

[myArray addObject:@"Abc"] 

NIE jest bezpieczny dla wątków.


Nie wiem, jak wygląda ostatni akapit, ale jest to po prostu zły, nie ma czegoś takiego jak „kopia prywatna”.
szczyt

13

Nie ma takiego słowa kluczowego „atomowy”

@property(atomic, retain) UITextField *userName;

Możemy użyć powyższych jak

@property(retain) UITextField *userName;

Zobacz pytanie Przepełnienie stosu Występują problemy, jeśli używam @property (atomowy, zachowaj) NSString * myString .


10
„Istnieje takie słowo kluczowe”, że słowo kluczowe nie jest domyślnie wymagane, a nawet, że wartość domyślna nie oznacza, że ​​słowo kluczowe nie istnieje.
Matthijn,

4
To jest niepoprawne. Słowo kluczowe istnieje. Ta odpowiedź jest myląca i zachęcam do jej usunięcia.
sethfri

12

atomowy (domyślnie)

Atomowy jest domyślny: jeśli nic nie wpiszesz, twoja własność jest atomowa. Właściwość atomowa jest gwarantowana, że ​​jeśli spróbujesz ją odczytać, otrzymasz prawidłową wartość. Nie daje żadnych gwarancji co do tego, jaka może być ta wartość, ale otrzymasz dobre dane, a nie tylko niepotrzebną pamięć. To pozwala ci to zrobić, jeśli masz wiele wątków lub wiele procesów wskazujących na jedną zmienną, jeden wątek może czytać, a drugi wątek może pisać. Jeśli trafią w tym samym czasie, wątek czytnika gwarantuje uzyskanie jednej z dwóch wartości: przed zmianą lub po zmianie. To, czego nie daje atom, to jakakolwiek gwarancja, którą z tych wartości możesz uzyskać. Atomic jest często mylony z bezpieczeństwem wątków i to nie jest poprawne. Musisz zagwarantować bezpieczeństwo swojego wątku na inne sposoby.

nieatomowy

Z drugiej strony, nieatomowy, jak można się domyślać, oznacza po prostu „nie rób tego atomowego”. To, co tracisz, to gwarancja, że ​​zawsze coś odzyskasz. Jeśli spróbujesz czytać w środku zapisu, możesz odzyskać śmieciowe dane. Ale z drugiej strony idziesz trochę szybciej. Ponieważ właściwości atomowe wymagają pewnej magii, aby zagwarantować odzyskanie wartości, są one nieco wolniejsze. Jeśli jest to właściwość, do której często się uzyskujesz, możesz zejść do trybu nieatomowego, aby upewnić się, że nie poniesiesz tej kary prędkości.

Zobacz więcej tutaj: https://realm.io/news/tmi-objective-c-property-attributes/


11

Domyślnym jestatomic , to oznacza to robi kosztować wydajność przy każdym użyciu nieruchomości, ale jest to bezpieczne dla wątków. To, co robi Cel-C, ustawia blokadę, więc tylko rzeczywisty wątek może uzyskać dostęp do zmiennej, o ile tylko setter / getter jest wykonywany.

Przykład z MRC właściwości z wewnętrznym ivar:

[_internal lock]; //lock
id result = [[value retain] autorelease];
[_internal unlock];
return result;

Te dwa ostatnie są takie same:

@property(atomic, retain) UITextField *userName;

@property(retain) UITextField *userName; // defaults to atomic

Z drugiej strony nonatomicnic nie dodaje do twojego kodu. Dlatego wątek jest bezpieczny tylko wtedy, gdy samodzielnie kodujesz mechanizm bezpieczeństwa.

@property(nonatomic, retain) UITextField *userName;

Słowa kluczowe wcale nie muszą być zapisywane jako pierwszy atrybut właściwości.

Nie zapominaj, że nie oznacza to, że cała nieruchomość jest bezpieczna dla wątków. Tylko wywołanie metody setter / getter jest. Ale jeśli użyjesz setera, a następnie gettera w tym samym czasie z 2 różnymi wątkami, może on również zostać zepsuty!


10

Zanim zaczniesz: musisz wiedzieć, że każdy obiekt w pamięci musi zostać zwolniony z pamięci, aby pojawił się nowy pisarz. Nie możesz po prostu pisać na czymś tak, jak na papierze. Państwo musi najpierw usunąć (dealloc) go, a następnie można napisać na nim. Jeśli w tej chwili usuwanie jest zakończone (lub w połowie wykonane) i nic jeszcze nie zostało zostało napisane (lub w połowie napisane), a Ty spróbujesz przeczytać, może to być bardzo problematyczne! Atomowa i nieatomowa pomoc w leczeniu tego problemu na różne sposoby.

Najpierw przeczytaj to pytanie, a następnie przeczytaj odpowiedź Bbum . Ponadto przeczytaj moje streszczenie.


atomic ZAWSZE gwarantuje

  • Jeśli dwie różne osoby chcą jednocześnie czytać i pisać, twój papier nie tylko spłonie! -> Twoja aplikacja nigdy się nie zawiesi, nawet w warunkach wyścigu.
  • Jeśli jedna osoba próbuje pisać i napisała tylko 4 z 8 liter do napisania, to nie można czytać w środku, odczyt można wykonać tylko wtedy, gdy wszystkie 8 liter jest napisane -> Nie nastąpi odczyt (pobranie) „wątek, który wciąż pisze”, tzn. jeśli do zapisania jest 8 bajtów, a zapisywane są tylko 4 bajty - do tego momentu nie wolno ci z niego czytać. Ale ponieważ powiedziałem, że to się nie zawiesi, to odczytałoby wartość automatycznie wydanego obiektu.
  • Jeśli przed piśmie ty już usunięte, co zostało wcześniej napisane na papierze, a następnie ktoś chce czytać ty może jeszcze czytać. W jaki sposób? Będziesz czytać z czegoś podobnego do kosza na Mac OS (ponieważ Kosz nie jest jeszcze w 100% wymazany ... jest w zawieszeniu) ---> Jeśli ThreadA ma czytać, a ThreadB już zwolnił przydzielanie do pisania, otrzymasz wartość z końcowej w pełni zapisanej wartości przez ThreadB lub uzyskaj coś z puli autorelease.

Liczniki przechowywania to sposób zarządzania pamięcią w Objective-C. Kiedy tworzysz obiekt, ma on liczbę zatrzymań równą 1. Gdy wysyłasz obiekt wiadomość zatrzymania, jego liczba zatrzymań jest zwiększana o 1. Gdy wysyłasz obiekt komunikat o zwolnieniu, jego liczba zatrzymań jest zmniejszana o 1. Kiedy wysłać obiektowi wiadomość z automatycznym wydaniem , jego liczba retencji jest zmniejszana o 1 na pewnym etapie w przyszłości. Jeśli liczba zatrzymań obiektu zostanie zmniejszona do 0, zostanie on cofnięty.

  • Atomic nie gwarantuje bezpieczeństwa wątku, chociaż jest przydatny do osiągnięcia bezpieczeństwa wątku. Bezpieczeństwo wątków zależy od sposobu pisania kodu / kolejki wątków, którą czytasz / piszesz. Gwarantuje tylko niezniszczalną wielowątkowość.

Co?! Czy wielowątkowość i bezpieczeństwo wątków są inne?

Tak. Wielowątkowość oznacza: wiele wątków może odczytywać udostępniony kawałek danych w tym samym czasie i nie ulegniemy awarii, ale nie gwarantuje to, że nie czytasz z wartości niepublikowanej ponownie. Bezpieczeństwo wątków gwarantuje, że to, co czytasz, nie jest automatycznie uwalniane. Powodem tego, że domyślnie nie robimy wszystkiego z atomu, jest to, że wiąże się to z obniżeniem wydajności i w większości przypadków tak naprawdę nie potrzebuje bezpieczeństwa wątków. Potrzebuje go kilka części naszego kodu, a dla tych kilku części musimy napisać nasz kod w sposób bezpieczny dla wątków, używając blokad, muteksu lub synchronizacji.


nonatomic

  • Ponieważ nie ma czegoś takiego jak kosz na śmieci w systemie Mac OS, nikt nie dba o to, czy zawsze dostajesz wartość (<- To może potencjalnie doprowadzić do awarii), ani nikogo to nie obchodzi, jeśli ktoś spróbuje przeczytać w połowie pisania (chociaż zapisywanie w połowie w pamięci bardzo różni się od zapisywania w połowie na papierze, w pamięci może dać szaloną, głupią wartość z przeszłości, podczas gdy na papierze widzisz tylko połowę tego, co zostało napisane) -> Nie gwarantuje, że nie upaść, ponieważ nie używa mechanizmu automatycznego uwalniania.
  • Nie gwarantuje przeczytania pełnych zapisanych wartości!
  • Jest szybszy niż atomowy

Ogólnie różnią się w 2 aspektach:

  • Awaria lub brak spowodowany posiadaniem lub brakiem puli autorelease.

  • Umożliwianie odczytu bezpośrednio w środku „jeszcze nieukończonego zapisu lub pustej wartości” lub niedozwolone i pozwalające na odczyt tylko wtedy, gdy wartość zostanie w pełni zapisana.


9

Jeśli używasz swojej właściwości w kodzie wielowątkowym, zobaczysz różnicę między atrybutami nieatomowymi i atomowymi. Nonatomowy jest szybszy niż atomowy, a atomowy jest bezpieczny dla nici, a nie nieatomowy.

Vijayendra Tripathi podała już przykład środowiska wielowątkowego.


9
  • -Atomic oznacza, że ​​tylko jeden wątek uzyskuje dostęp do zmiennej (typ statyczny).
  • -Atomika jest bezpieczna dla wątków.
  • -Ale ma niską wydajność

Jak zadeklarować:

Ponieważ atom jest domyślny,

@property (retain) NSString *name;

ORAZ w pliku implementacji

self.name = @"sourov";

Załóżmy, że zadanie związane z trzema właściwościami to

 @property (retain) NSString *name;
 @property (retain) NSString *A;
 @property (retain) NSString *B;
 self.name = @"sourov";

Wszystkie właściwości działają równolegle (jak asynchronicznie).

Jeśli wywołasz „imię” z wątku A ,

I

W tym samym czasie, jeśli zadzwonisz

[self setName:@"Datta"]

z wątku B ,

Teraz Jeśli właściwość * name jest niepatomowa, to

  • Zwróci wartość „Datta” dla A
  • Zwróci wartość „Datta” dla B

Dlatego non-atomowy nazywa się niebezpiecznym wątkiem. Ale jest szybki w działaniu ze względu na równoległe wykonywanie

Teraz Jeśli właściwość * name jest atomowa

  • Zapewni to wartość „Sourov” dla A.
  • Następnie zwróci wartość „Datta” dla B

Właśnie dlatego atom nazywa się Bezpieczny dla wątków i dlatego nazywa się Bezpieczny do odczytu i zapisu

Taka operacja sytuacyjna zostanie wykonana szeregowo. I powolny w działaniu

- Nonatomic oznacza dostęp do wielu wątków zmiennej (typ dynamiczny).

- Nonatomic jest niebezpieczny dla nici.

- ale działa szybko

-Nieatomowe NIE jest zachowaniem domyślnym, musimy dodać nieatomowe słowo kluczowe w atrybucie właściwości.

Dla In Swift Potwierdzenie, że właściwości Swift nie są anatomiczne w sensie ObjC. Jednym z powodów jest zastanowienie się, czy atomowość według właściwości jest wystarczająca dla twoich potrzeb.

Odniesienie: https://forums.developer.apple.com/thread/25642

Więcej informacji można znaleźć na stronie http://rdcworld-iphone.blogspot.in/2012/12/variable-property-attributes-or.html


4
Jak wielu wielu wielu innych powiedziało, NIEatomic jest bezpieczne dla wątków! Jest bardziej odporny na problemy z nitkami, ale nie jest bezpieczny. Po prostu zapewnia, że ​​otrzymasz całą wartość, czyli „poprawną” wartość (poziom binarny), ale w żadnym wypadku nie zapewni, że jest to bieżąca i „poprawna” wartość dla Twojej logiki biznesowej (może to być wartość przeszła i nieważne z powodu logiki).
Alejandro Iván

6

Atomowość atomowa (domyślnie)

Atomowy jest domyślny: jeśli nic nie wpiszesz, twoja własność jest atomowa. Właściwość atomowa jest gwarantowana, że ​​jeśli spróbujesz ją odczytać, otrzymasz prawidłową wartość. Nie daje żadnych gwarancji co do tego, jaka może być ta wartość, ale otrzymasz dobre dane, a nie tylko niepotrzebną pamięć. To pozwala ci to zrobić, jeśli masz wiele wątków lub wiele procesów wskazujących na jedną zmienną, jeden wątek może czytać, a drugi wątek może pisać. Jeśli trafią w tym samym czasie, wątek czytnika gwarantuje uzyskanie jednej z dwóch wartości: przed zmianą lub po zmianie. To, czego nie daje atom, to jakakolwiek gwarancja, którą z tych wartości możesz uzyskać. Atomic jest często mylony z bezpieczeństwem wątków i to nie jest poprawne. Musisz zagwarantować bezpieczeństwo swojego wątku na inne sposoby.

nieatomowy

Z drugiej strony, nieatomowy, jak można się domyślać, oznacza po prostu „nie rób tego atomowego”. To, co tracisz, to gwarancja, że ​​zawsze coś odzyskasz. Jeśli spróbujesz czytać w środku zapisu, możesz odzyskać śmieciowe dane. Ale z drugiej strony idziesz trochę szybciej. Ponieważ właściwości atomowe wymagają pewnej magii, aby zagwarantować odzyskanie wartości, są one nieco wolniejsze. Jeśli jest to właściwość, do której często się uzyskujesz, możesz zejść do trybu nieatomowego, aby upewnić się, że nie poniesiesz tej kary prędkości. Dostęp

dzięki uprzejmości https://academy.realm.io/posts/tmi-objective-c-property-attributes/

Atrybuty właściwości atomowości (atomowa i nieatomowa) nie są odzwierciedlone w odpowiedniej deklaracji właściwości Swift, ale gwarancje atomowości implementacji celu C nadal obowiązują, gdy do importowanej właściwości można uzyskać dostęp z Swift.

Tak więc - jeśli zdefiniujesz właściwość atomową w Celu C, pozostanie ona atomowa, gdy zostanie użyta przez Swift.

dzięki uprzejmości https://medium.com/@YogevSitton/atomic-vs-non-atomic-properties-crash-course-d11c23f4366c


5

Właściwość atomowa zapewnia zachowanie w pełni zainicjowanej wartości niezależnie od tego, ile wątków robi na niej getter i setter.

Właściwość nieatomowa określa, że ​​zsyntetyzowane akcesoria po prostu ustawiają lub zwracają wartość bezpośrednio, bez żadnych gwarancji, co się stanie, jeśli ta sama wartość będzie dostępna jednocześnie z różnych wątków.


3

Atomowa oznacza, że ​​tylko jeden wątek może uzyskać dostęp do zmiennej jednocześnie (typ statyczny). Atomic jest bezpieczny dla wątków, ale działa wolno.

Nonatomic oznacza, że ​​wiele wątków może uzyskać dostęp do zmiennej w tym samym czasie (typ dynamiczny). Nonatomic jest niebezpieczny dla nici, ale jest szybki.


1

Jeśli używasz atomu, oznacza to, że wątek będzie bezpieczny i tylko do odczytu. Jeśli używasz nonatomic, oznacza to, że wiele wątków ma dostęp do zmiennej i jest niebezpiecznie wątek, ale jest wykonywany szybko, wykonuje operacje odczytu i zapisu; to jest typ dynamiczny.


1

Prawda jest taka, że ​​używają blokady spinowej do implementacji własności atomowej. Kod jak poniżej:

 static inline void reallySetProperty(id self, SEL _cmd, id newValue, 
      ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy) 
    {
        id oldValue;
        id *slot = (id*) ((char*)self + offset);

        if (copy) {
            newValue = [newValue copyWithZone:NULL];
        } else if (mutableCopy) {
            newValue = [newValue mutableCopyWithZone:NULL];
        } else {
            if (*slot == newValue) return;
            newValue = objc_retain(newValue);
        }

        if (!atomic) {
            oldValue = *slot;
            *slot = newValue;
        } else {
            spin_lock_t *slotlock = &PropertyLocks[GOODHASH(slot)];
            _spin_lock(slotlock);
            oldValue = *slot;
            *slot = newValue;        
            _spin_unlock(slotlock);
        }

        objc_release(oldValue);
    }

0

Aby uprościć całe zamieszanie, zrozummy blokadę mutex.

Mutex lock, jak sama nazwa, blokuje zmienność obiektu. Jeśli więc obiekt ma dostęp do klasy, żadna inna klasa nie może uzyskać dostępu do tego samego obiektu.

W iOS @sychronisezapewnia również blokadę mutex. Teraz działa w trybie FIFO i zapewnia, że ​​dwie klasy współużytkujące tę samą instancję nie wpływają na przepływ. Jeśli jednak zadanie jest w głównym wątku, unikaj uzyskiwania dostępu do obiektu za pomocą właściwości atomowych, ponieważ może on zawierać interfejs użytkownika i obniżyć wydajność.


-1

Atomowa: Zapewnij bezpieczeństwo wątku, blokując wątek za pomocą NSLOCK.

Bezatomowy: Nie zapewnia bezpieczeństwa wątku, ponieważ nie ma mechanizmu blokującego wątek.


-1

Właściwości atomowe : - Gdy zmienna przypisana do właściwości atomowej, co oznacza, że ​​ma dostęp tylko do jednego wątku i będzie bezpieczna dla wątków i będzie dobra z punktu widzenia wydajności, będzie miała domyślne zachowanie.

Właściwości nieatomowe: - Gdy zmienna przypisana do właściwości atomowej oznacza, że ​​ma dostęp do wielu wątków i nie będzie bezpieczna dla wątków i będzie wolna w perspektywie wydajności, będzie zachowywać się domyślnie, a gdy dwa różne wątki będą chciały uzyskać dostęp do zmiennej w tym samym czasie da nieoczekiwane rezultaty.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.