Was ist der Unterschied zwischen den atomaren und nichtatomaren Attributen?


Antworten:


1761

Die letzten beiden sind identisch; "atomic" ist das Standardverhalten ( beachten Sie, dass es sich nicht um ein Schlüsselwort handelt; es wird nur durch das Fehlen vonnonatomic - angegeben, dasatomic in neueren Versionen von llvm / clang als Schlüsselwort hinzugefügt wurde).

Unter der Annahme, dass Sie die Methodenimplementierungen @synthesisieren, ändert Atomic vs. Non-Atomic den generierten Code. Wenn Sie Ihren eigenen Setter / Getter schreiben, sind Atomic / Nonatomic / Retain / Assign / Copy nur ratsam. (Hinweis: @synthesize ist jetzt das Standardverhalten in neueren Versionen von LLVM. Es ist auch nicht erforderlich, Instanzvariablen zu deklarieren. Sie werden ebenfalls automatisch synthetisiert und _ihrem Namen vorangestellt, um einen versehentlichen direkten Zugriff zu verhindern.)

Mit "atomar" stellt der synthetisierte Setter / Getter sicher, dass immer ein ganzer Wert vom Getter zurückgegeben oder vom Setter gesetzt wird, unabhängig von der Setteraktivität in einem anderen Thread. Das heißt, wenn sich Thread A in der Mitte des Getters befindet, während Thread B den Setter aufruft, wird ein tatsächlich realisierbarer Wert - höchstwahrscheinlich ein automatisch freigegebenes Objekt - an den Aufrufer in A zurückgegeben.

In nonatomicwerden keine solchen Garantien gegeben. Somit nonatomicist erheblich schneller als "atomar".

Was "atomar" nicht tut, ist, irgendwelche Garantien über die Gewindesicherheit zu geben. Wenn Thread A den Getter gleichzeitig mit Thread B und C aufruft, die den Setter mit unterschiedlichen Werten aufrufen, kann Thread A einen der drei zurückgegebenen Werte erhalten - den vor dem Aufrufen von Setzern oder einen der an die Setter übergebenen Werte in B und C. Ebenso kann das Objekt mit dem Wert von B oder C enden, keine Möglichkeit zu sagen.

Die Gewährleistung der Datenintegrität - eine der Hauptherausforderungen der Multithread-Programmierung - wird auf andere Weise erreicht.

Hinzu kommt:

atomicity einer einzelnen Eigenschaft kann auch keine Thread-Sicherheit garantieren, wenn mehrere abhängige Eigenschaften im Spiel sind.

Erwägen:

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

In diesem Fall könnte Thread A das Objekt durch Aufrufen setFirstName:und anschließendes Aufrufen umbenennen setLastName:. In der Zwischenzeit kann Thread B fullNamezwischen den beiden Aufrufen von Thread A aufrufen und erhält den neuen Vornamen in Verbindung mit dem alten Nachnamen.

Um dies zu beheben, benötigen Sie ein Transaktionsmodell . Dh eine andere Art der Synchronisation und / oder des Ausschlusses, mit der der Zugriff ausgeschlossen werden kann, fullNamewährend die abhängigen Eigenschaften aktualisiert werden.


21
Wann möchten Sie angesichts der Tatsache, dass jeder thread-sichere Code seine eigene Sperrung usw. ausführt, atomare Eigenschaftszugriffsmethoden verwenden? Ich habe Probleme, an ein gutes Beispiel zu denken.
Daniel Dickison

8
@bbum macht Sinn. Ich mag Ihren Kommentar zu einer anderen Antwort, dass Thread-Sicherheit eher ein Problem auf Modellebene ist. Aus einer IBM Thread-Sicherheitsdefinition: ibm.co/yTEbjY "Wenn eine Klasse korrekt implementiert ist, was eine andere Art zu sagen ist, dass sie ihrer Spezifikation entspricht, keine Abfolge von Operationen (Lesen oder Schreiben von öffentlichen Feldern und Aufrufen öffentlicher Methoden) Objekte dieser Klasse sollten in der Lage sein, das Objekt in einen ungültigen Zustand zu versetzen, zu beobachten, dass sich das Objekt in einem ungültigen Zustand befindet, oder gegen eine der Invarianten, Vorbedingungen oder Nachbedingungen der Klasse zu verstoßen. "
Ben Flynn

6
Hier ist ein Beispiel ähnlich dem von @StevenKramer: Ich habe ein Beispiel @property NSArray* astronomicalEvents;, das Daten auflistet, die ich in der Benutzeroberfläche anzeigen möchte. Wenn die Anwendung startet und der Zeiger auf ein leeres Array zeigt, ruft die App Daten aus dem Web ab. Wenn die Webanforderung abgeschlossen ist (in einem anderen Thread), erstellt die App ein neues Array und setzt die Eigenschaft atomar auf einen neuen Zeigerwert. Es ist threadsicher und ich musste keinen Sperrcode schreiben, es sei denn, mir fehlt etwas. Scheint mir ziemlich nützlich zu sein.
Bugloaf

10
@HotLicks Ein weiterer Spaß; Bei bestimmten Architekturen (ich kann mich nicht erinnern, welche) werden 64-Bit-Werte, die als Argument übergeben wurden, möglicherweise zur Hälfte in einem Register und zur Hälfte auf dem Stapel übergeben. atomicverhindert Cross-Thread-Halbwertlesungen. (Das war ein lustiger Fehler zu finden.)
bbum

8
@congliu Thread A gibt ein Objekt ohne retain/autoreleaseTanz zurück. Thread B gibt das Objekt frei. Faden A boomt . atomicstellt sicher, dass Thread A eine starke Referenz (eine Anzahl von +1 beibehalten) für den Rückgabewert hat.
bbum

360

Dies wird in der Apple- Dokumentation erläutert. Nachfolgend finden Sie einige Beispiele dafür, was tatsächlich passiert.

Beachten Sie, dass es kein "atomares" Schlüsselwort gibt. Wenn Sie nicht "nichtatomar" angeben, ist die Eigenschaft atomar, aber die explizite Angabe von "atomar" führt zu einem Fehler.

Wenn Sie nicht "nichtatomar" angeben, ist die Eigenschaft atomar, Sie können jedoch in neueren Versionen explizit "atomar" angeben, wenn Sie möchten.

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

- (UITextField *) userName {
    return userName;
}

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

Jetzt ist die atomare Variante etwas komplizierter:

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

Grundsätzlich muss die atomare Version gesperrt werden, um die Thread-Sicherheit zu gewährleisten, und erhöht auch die Ref-Anzahl für das Objekt (und die Anzahl der Autoreleases, um es auszugleichen), damit das Objekt für den Aufrufer garantiert existiert, andernfalls dort Dies ist eine mögliche Race-Bedingung, wenn ein anderer Thread den Wert festlegt und die Ref-Anzahl auf 0 fällt.

Es gibt tatsächlich eine große Anzahl verschiedener Varianten, wie diese Dinge funktionieren, abhängig davon, ob die Eigenschaften skalare Werte oder Objekte sind und wie beibehalten, kopieren, schreibgeschützt, nichtatomar usw. interagieren. Im Allgemeinen wissen die Eigenschaftssynthesizer nur, wie man für alle Kombinationen das "Richtige" macht.


8
@ Louis Gerbarg: Ich glaube, Ihre Version des (nichtatomaren, beibehaltenen) Setzers wird nicht richtig funktionieren, wenn Sie versuchen, dasselbe Objekt zuzuweisen (dh: Benutzername == Benutzername_)
Florin

5
Ihr Code ist leicht irreführend. Es gibt keine Garantie dafür, welche Atom-Getter / Setter synchronisiert sind. Kritisch ist, @property (assign) id delegate;wird auf nichts synchronisiert (iOS SDK GCC 4.2 ARM -Os), was bedeutet, dass es einen Wettlauf zwischen [self.delegate delegateMethod:self];und gibt foo.delegate = nil; self.foo = nil; [super dealloc];. Siehe stackoverflow.com/questions/917884/…
tc.

@fyolnish Ich bin nicht sicher, was _val/ valsind, aber nein, nicht wirklich. Der Getter für ein Atom copy/ eine retainEigenschaft muss sicherstellen, dass er kein Objekt zurückgibt, dessen Refcount Null wird, da der Setter in einem anderen Thread aufgerufen wird. Dies bedeutet im Wesentlichen, dass er den ivar lesen und beibehalten muss, während er sicherstellt, dass der Setter dies nicht getan hat überschrieben und freigegeben, und dann automatisch freigeben, um die Aufbewahrung auszugleichen. Dies bedeutet im Wesentlichen, dass sowohl der Getter als auch der Setter eine Sperre verwenden müssen (wenn das Speicherlayout festgelegt wurde, sollte dies mit CAS2-Anweisungen möglich sein; leider -retainhandelt es sich um einen Methodenaufruf).
tc.

@tc Es ist schon eine Weile her, aber was ich schreiben wollte, war wahrscheinlich Folgendes : gist.github.com/fjolnir/5d96b3272c6255f6baae Aber ja, es ist möglich, dass der alte Wert von einem Leser gelesen wird, bevor setFoo: zurückkehrt und vor dem veröffentlicht wird Leser gibt es zurück. Aber wenn der Setter -autorelease anstelle von -release verwenden würde, würde dies möglicherweise das Problem beheben.
Fjölnir

@fyolnish Leider nein: Das wird automatisch auf dem Thread des Setters freigegeben, während es auf dem Thread des Getters automatisch freigegeben werden muss. Es sieht auch so aus, als ob es eine (geringe) Chance gibt, dass der Stapel ausgeht, weil Sie die Rekursion verwenden.
tc.

170

Atomic

  • ist das Standardverhalten
  • stellt sicher, dass der aktuelle Prozess von der CPU abgeschlossen wird, bevor ein anderer Prozess auf die Variable zugreift
  • ist nicht schnell, da es sicherstellt, dass der Prozess vollständig abgeschlossen ist

Nicht atomar

  • ist NICHT das Standardverhalten
  • schneller (für synthetisierten Code, dh für Variablen, die mit @property und @synthesize erstellt wurden)
  • nicht threadsicher
  • kann zu unerwartetem Verhalten führen, wenn zwei verschiedene Prozesse gleichzeitig auf dieselbe Variable zugreifen

137

Der beste Weg, um den Unterschied zu verstehen, ist das folgende Beispiel.

Angenommen, es gibt eine atomare Zeichenfolgeeigenschaft mit dem Namen "name". Wenn Sie [self setName:@"A"]von Thread A, [self setName:@"B"]von Thread B und [self name]von Thread C aufrufen , werden alle Operationen an verschiedenen Threads seriell ausgeführt. Dies bedeutet, dass ein Thread einen Setter ausführt oder Getter, dann warten andere Threads.

Dies macht das Lesen / Schreiben der Eigenschaft "Name" sicher, aber wenn ein anderer Thread, D, [name release]gleichzeitig aufruft, kann diese Operation einen Absturz verursachen, da hier kein Setter / Getter-Aufruf beteiligt ist. Dies bedeutet, dass ein Objekt schreib- / schreibsicher (ATOMIC) ist, jedoch nicht threadsicher, da andere Threads gleichzeitig alle Arten von Nachrichten an das Objekt senden können. Der Entwickler sollte die Thread-Sicherheit für solche Objekte gewährleisten.

Wenn die Eigenschaft "Name" nichtatomar war, werden alle Threads im obigen Beispiel - A, B, C und D gleichzeitig ausgeführt und erzeugen ein unvorhersehbares Ergebnis. Im Fall von Atomic wird entweder eines von A, B oder C zuerst ausgeführt, aber D kann immer noch parallel ausgeführt werden.


116

Die Syntax und Semantik sind bereits durch andere hervorragende Antworten auf diese Frage gut definiert. Da Ausführung und Leistung nicht gut detailliert sind, werde ich meine Antwort hinzufügen.

Was ist der funktionale Unterschied zwischen diesen 3?

Ich hatte Atomic immer als Standard angesehen, ziemlich neugierig. Auf der Abstraktionsebene, auf der wir arbeiten, ist die Verwendung atomarer Eigenschaften für eine Klasse als Vehikel zur Erzielung einer 100% igen Thread-Sicherheit ein Eckfall. Für wirklich korrekte Multithread-Programme ist mit ziemlicher Sicherheit ein Eingreifen des Programmierers erforderlich. In der Zwischenzeit wurden Leistungsmerkmale und Ausführung noch nicht detailliert beschrieben. Nachdem ich im Laufe der Jahre einige stark multithreaded Programme geschrieben hatte, hatte ich meine Eigenschaften als nonatomicdie ganze Zeit deklariert, weil Atomic für keinen Zweck sinnvoll war. Während der Diskussion der Details der atomaren und nichtatomaren Eigenschaften dieser Frage stieß ich bei einigen Profilen auf einige merkwürdige Ergebnisse.

Ausführung

OK. Als erstes möchte ich klarstellen, dass die Sperrimplementierung implementierungsdefiniert und abstrahiert ist. Louis verwendet @synchronized(self)in seinem Beispiel - ich habe dies als eine häufige Quelle der Verwirrung gesehen. Die Implementierung ist nicht tatsächlich verwenden @synchronized(self); Es werden Spin-Sperren auf Objektebene verwendet . Louis 'Illustration ist gut für eine hochrangige Illustration mit Konstrukten, mit denen wir alle vertraut sind, aber es ist wichtig zu wissen, dass sie nicht verwendet wird @synchronized(self).

Ein weiterer Unterschied besteht darin, dass die atomaren Eigenschaften Ihre Objekte im Getter beibehalten / freigeben.

Performance

Hier ist der interessante Teil: Die Leistung bei der Verwendung von atomaren Eigenschaftszugriffen in unbestrittenen Fällen (z. B. Single-Threaded-Fällen) kann in einigen Fällen sehr schnell sein. In weniger als idealen Fällen kann die Verwendung von atomaren Zugriffen mehr als das 20-fache des Overheads kosten nonatomic. Während der umstrittene Fall mit 7 Threads für die Drei-Byte-Struktur (2,2 GHz Core i7 Quad Core, x86_64) 44-mal langsamer war . Die Drei-Byte-Struktur ist ein Beispiel für eine sehr langsame Eigenschaft.

Interessante Randnotiz: Benutzerdefinierte Accessoren der Drei-Byte-Struktur waren 52-mal schneller als die synthetisierten Atom-Accessoren; oder 84% der Geschwindigkeit synthetisierter nichtatomarer Accessoren.

Objekte in umstrittenen Fällen können auch das 50-fache überschreiten.

Aufgrund der Anzahl der Optimierungen und Variationen bei den Implementierungen ist es ziemlich schwierig, die tatsächlichen Auswirkungen in diesen Kontexten zu messen. Möglicherweise hören Sie häufig etwas wie "Vertrauen Sie ihm, es sei denn, Sie profilieren und stellen fest, dass es ein Problem ist". Aufgrund der Abstraktionsebene ist es tatsächlich ziemlich schwierig, die tatsächlichen Auswirkungen zu messen. Das Abrufen der tatsächlichen Kosten aus Profilen kann sehr zeitaufwändig und aufgrund von Abstraktionen sehr ungenau sein. Auch ARC vs MRC können einen großen Unterschied machen.

Lassen Sie uns also einen Schritt zurücktreten und uns nicht auf die Implementierung von Eigenschaftszugriffen konzentrieren. Wir werden die üblichen Verdächtigen wie einbeziehen objc_msgSendund einige reale High-Level-Ergebnisse für viele Aufrufe eines NSStringGetters in unbestrittenen Fällen untersuchen (Werte in Sekunden):

  • MRC | nichtatomar | manuell implementierte Getter: 2
  • MRC | nichtatomar | synthetisierter Getter: 7
  • MRC | atomar | synthetisierter Getter: 47
  • ARC | nichtatomar | synthetisierter Getter: 38 (Hinweis: ARC fügt hier Ref Count Count hinzu)
  • ARC | atomar | synthetisierter Getter: 47

Wie Sie wahrscheinlich erraten haben, trägt die Aktivität / das Radfahren der Referenzzählung wesentlich zur Atomik und unter ARC bei. Sie würden auch größere Unterschiede in umstrittenen Fällen sehen.

Obwohl ich der Leistung große Aufmerksamkeit schenke, sage ich immer noch Semantik zuerst! . In der Zwischenzeit hat die Leistung für viele Projekte eine niedrige Priorität. Die Kenntnis der Ausführungsdetails und der Kosten der von Ihnen verwendeten Technologien schadet jedoch sicherlich nicht. Sie sollten die richtige Technologie für Ihre Bedürfnisse, Zwecke und Fähigkeiten verwenden. Dies erspart Ihnen hoffentlich einige Stunden Vergleiche und hilft Ihnen, eine fundiertere Entscheidung bei der Gestaltung Ihrer Programme zu treffen.


MRC | atomar | synthetisierter Getter: 47 ARC | atomar | synthetisierter Getter: 47 Was macht sie gleich? Sollte ARC nicht mehr Overhead haben?
SDEZero

2
Wenn also atomare Eigenschaften schlecht sind, sind sie Standard. So erhöhen Sie den Boilerplate-Code?
Kunal Balani

@ LearnCocos2D Ich habe gerade auf 10.8.5 auf demselben Computer getestet und auf 10.8 für den unbestrittenen Einzelthread-Fall mit einem NSStringnicht unsterblichen Fall abgezielt : -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%- Die Ergebnisse sind heute etwas anders. Ich habe keine @synchronizedVergleiche angestellt. @synchronizedist semantisch anders, und ich halte es nicht für ein gutes Werkzeug, wenn Sie nicht triviale gleichzeitige Programme haben. Wenn Sie Geschwindigkeit brauchen, vermeiden Sie @synchronized.
Justin

Hast du diesen Test irgendwo online? Ich
füge

@ LearnCocos2D Ich habe sie nicht für den menschlichen Verzehr vorbereitet, sorry.
Justin

95

Atomic = Gewindesicherheit

Nicht atomar = Keine Gewindesicherheit

Gewindesicherheit:

Instanzvariablen sind threadsicher, wenn sie sich beim Zugriff von mehreren Threads aus korrekt verhalten, unabhängig von der Planung oder Verschachtelung der Ausführung dieser Threads durch die Laufzeitumgebung und ohne zusätzliche Synchronisation oder andere Koordination seitens des aufrufenden Codes.

In unserem Kontext:

Wenn ein Thread den Wert der Instanz ändert, steht der geänderte Wert allen Threads zur Verfügung, und es kann jeweils nur ein Thread den Wert ändern.

Verwendungszweck atomic:

Wenn auf die Instanzvariable in einer Multithread-Umgebung zugegriffen werden soll.

Implikation von atomic:

Nicht so schnell, nonatomicweil nonatomices zur Laufzeit keine Watchdog-Arbeit erfordert.

Verwendungszweck nonatomic:

Wenn die Instanzvariable nicht von mehreren Threads geändert wird, können Sie sie verwenden. Es verbessert die Leistung.


3
Alles, was Sie hier sagen, ist richtig, aber der letzte Satz ist für die heutige Programmierung im Wesentlichen "falsch", Dura. Es ist wirklich unvorstellbar, dass Sie versuchen würden, die Leistung auf diese Weise zu verbessern. (Ich meine, bevor Sie innerhalb von Lichtjahren dazu gekommen sind, würden Sie "ARC nicht verwenden", "NSString nicht verwenden, weil es langsam ist!" Und so weiter.) Um ein extremes Beispiel zu geben, wäre es, als würde man "Team" sagen. Fügen Sie keine Kommentare in den Code ein, da dies uns verlangsamt. " Es gibt keine realistische Entwicklungspipeline, in der Sie die (nicht vorhandenen) theoretischen Leistungssteigerungen aus Gründen der Unzuverlässigkeit wünschen würden.
Fattie

3
@ JoeBlow Es ist eine Tatsache, dass Sie es hier überprüfen können Developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
Durai Amuthan.H

1
Durai, FWIW, dieser Link widerspricht direkt Ihrer These von „Atomic = Thread Safety“. In dem Dokument sagt Apple ausdrücklich: "Eigenschaftsatomarität ist nicht gleichbedeutend mit der Thread-Sicherheit eines Objekts." In der Praxis reicht Atomic selten aus, um die Gewindesicherheit zu erreichen.
Rob

69

Ich habe hier eine ziemlich gute Erklärung für atomare und nichtatomare Eigenschaften gefunden . Hier ist ein relevanter Text aus demselben:

'atomar' bedeutet, dass es nicht zerlegt werden kann. In Bezug auf Betriebssystem / Programmierung kann ein atomarer Funktionsaufruf nicht unterbrochen werden. Die gesamte Funktion muss ausgeführt werden und darf nicht durch die übliche Kontextumschaltung des Betriebssystems aus der CPU ausgelagert werden, bis sie abgeschlossen ist. Nur für den Fall, dass Sie es nicht wussten: Da die CPU jeweils nur eine Aufgabe ausführen kann, dreht das Betriebssystem den Zugriff auf die CPU in wenigen Zeitabschnitten auf alle laufenden Prozesse, um die Illusion zu erzeugenvon Multitasking. Der CPU-Scheduler kann (und tut) einen Prozess zu jedem Zeitpunkt seiner Ausführung unterbrechen - sogar während eines mittleren Funktionsaufrufs. Für Aktionen wie das Aktualisieren gemeinsam genutzter Zählervariablen, bei denen zwei Prozesse versuchen könnten, die Variable gleichzeitig zu aktualisieren, müssen sie "atomar" ausgeführt werden, dh jede Aktualisierungsaktion muss vollständig abgeschlossen sein, bevor ein anderer Prozess auf die Variable übertragen werden kann ZENTRALPROZESSOR.

Ich würde also vermuten, dass atomar in diesem Fall bedeutet, dass die Attributlesemethoden nicht unterbrochen werden können. Dies bedeutet, dass die von der Methode gelesenen Variablen ihren Wert nicht zur Hälfte ändern können, weil ein anderer Thread / Aufruf / eine andere Funktion abgerufen wird auf die CPU getauscht.

Da die atomicVariablen nicht unterbrochen werden können, ist der von ihnen zu jedem Zeitpunkt enthaltene Wert (Thread-Sperre) garantiert nicht beschädigt , obwohl durch die Sicherstellung dieser Thread-Sperre der Zugriff auf sie langsamer wird. non-atomicVariablen hingegen geben keine solche Garantie, bieten jedoch den Luxus eines schnelleren Zugriffs. Um es zusammenzufassen, gehen non-atomicSie zu, wenn Sie wissen, dass nicht mehrere Threads gleichzeitig auf Ihre Variablen zugreifen, und beschleunigen Sie die Arbeit.


1
Link ist unterbrochen. ; (
Rob

Das ist das Problem mit Links :( Zum Glück habe ich den relevanten Text in meiner Antwort zitiert
tipycalFlow

67

Nachdem ich so viele Artikel gelesen, Stapelüberlauf-Beiträge verfasst und Demo-Anwendungen zum Überprüfen von Attributen variabler Eigenschaften erstellt hatte, entschied ich mich, alle Attributinformationen zusammenzustellen:

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

Im Artikel Variable Eigenschaftsattribute oder Modifikatoren in iOS finden Sie alle oben genannten Attribute, und das wird Ihnen definitiv helfen.

  1. atomic

    • atomic bedeutet, dass nur ein Thread auf die Variable zugreift (statischer Typ).
    • atomic ist threadsicher.
    • Aber die Leistung ist langsam
    • atomic ist das Standardverhalten
    • Atomic Accessors in einer Umgebung ohne Müllabfuhr (dh bei Verwendung von Retain / Release / Autorelease) verwenden eine Sperre, um sicherzustellen, dass ein anderer Thread die korrekte Einstellung / das Abrufen des Werts nicht beeinträchtigt.
    • Es ist eigentlich kein Schlüsselwort.

    Beispiel:

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

    • nonatomic bedeutet, dass mehrere Threads auf die Variable zugreifen (dynamischer Typ).
    • nonatomic ist thread-unsicher.
    • Aber es ist schnell in der Leistung
    • nonatomicist NICHT Standardverhalten. Wir müssen das nonatomicSchlüsselwort im Eigenschaftsattribut hinzufügen .
    • Dies kann zu unerwartetem Verhalten führen, wenn zwei verschiedene Prozesse (Threads) gleichzeitig auf dieselbe Variable zugreifen.

    Beispiel:

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

Wie können beide zuweisen und stark / beibehalten standardmäßig sein?
BangOperator

stark kommt mit ARC, behalten war Standard vor ARC
abdullahselek

56

Atomic:

Atomic garantiert, dass der Zugriff auf das Grundstück auf atomare Weise erfolgt. Beispielsweise werden immer vollständig initialisierte Objekte zurückgegeben. Jedes Abrufen / Festlegen einer Eigenschaft in einem Thread muss abgeschlossen sein, bevor ein anderer darauf zugreifen kann.

Wenn Sie sich vorstellen, dass die folgende Funktion auf zwei Threads gleichzeitig ausgeführt wird, können Sie sehen, warum die Ergebnisse nicht schön sind.

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

  ...
}

Vorteile: Die Rückgabe vollständig initialisierter Objekte ist bei Multithreading die beste Wahl.

Nachteile: Leistungseinbußen, macht die Ausführung etwas langsamer

Nicht atomar:

Im Gegensatz zu Atomic wird nicht jedes Mal eine vollständig initialisierte Objektrückgabe sichergestellt.

Vorteile: Extrem schnelle Ausführung.

Nachteile: Chancen auf Müllwert bei Multithreading.


5
Dieser Kommentar macht nicht viel Sinn. Könntest Du das erläutern? Wenn Sie sich Beispiele auf der Apple-Website ansehen, wird das atomare Schlüsselwort für das Objekt synchronisiert, während dessen Eigenschaften aktualisiert werden.
Andrew Grant

52

Einfachste Antwort zuerst: Es gibt keinen Unterschied zwischen Ihren zweiten beiden Beispielen. Standardmäßig sind Eigenschaftszugriffsatome atomar.

Atomic Accessors in einer Umgebung ohne Müllabfuhr (dh bei Verwendung von Retain / Release / Autorelease) verwenden eine Sperre, um sicherzustellen, dass ein anderer Thread die korrekte Einstellung / das Abrufen des Werts nicht beeinträchtigt.

Weitere Informationen und weitere Überlegungen zum Erstellen von Multithread-Apps finden Sie im Abschnitt " Leistung und Threading " der Apple Objective-C 2.0-Dokumentation.


8
Zwei Gründe. Zunächst einmal wird für synthetisierten Code schneller generiert (aber kein threadsicherer Code). Zweitens, wenn Sie Kunden-Accessoren schreiben, die nicht atomar sind, können Sie jedem zukünftigen Benutzer mitteilen, dass der Code beim Lesen seiner Benutzeroberfläche nicht atomar ist, ohne sie zu implementieren.
Louis Gerbarg


31

Atomic bedeutet, dass nur ein Thread auf die Variable zugreift (statischer Typ). Atomic ist threadsicher, aber langsam.

Nichtatomar bedeutet, dass mehrere Threads auf die Variable zugreifen (dynamischer Typ). Nichtatomar ist threadsicher, aber schnell.


14

Atomic ist threadsicher , langsam und sicher (nicht garantiert) dass nur der gesperrte Wert bereitgestellt wird, unabhängig davon, wie viele Threads versuchen, über dieselbe Zone zuzugreifen. Bei Verwendung von Atomic wird ein in diese Funktion geschriebener Code zum Teil des kritischen Abschnitts, für den jeweils nur ein Thread ausgeführt werden kann.

Es gewährleistet nur die Gewindesicherheit; es garantiert das nicht. Was ich meine ist, dass Sie einen erfahrenen Fahrer für Ihr Auto einstellen, der jedoch nicht garantiert, dass das Auto keinen Unfall erleidet. Die Wahrscheinlichkeit bleibt jedoch am geringsten.

Atomic - es kann nicht zerlegt werden, daher wird das Ergebnis erwartet. Mit nonatomic - Wenn ein anderer Thread auf die Speicherzone zugreift, kann er diese ändern, sodass das Ergebnis unerwartet ist.

Code Talk:

Atomic macht Getter und Setter des Property Thread sicher. Zum Beispiel, wenn Sie geschrieben haben:

self.myProperty = value;

ist threadsicher.

[myArray addObject:@"Abc"] 

ist NICHT threadsicher.


Ich weiß nicht, wie der letzte Absatz kommt, aber es ist einfach falsch, es gibt keine "private Kopie".
Peak

13

Es gibt kein solches Schlüsselwort "atomar"

@property(atomic, retain) UITextField *userName;

Wir können die oben genannten wie verwenden

@property(retain) UITextField *userName;

Siehe Frage zum Stapelüberlauf . Ich erhalte Probleme, wenn ich @property (atomar, beibehalten) NSString * myString verwende .


10
"Es gibt ein solches Schlüsselwort", dass das Schlüsselwort standardmäßig nicht erforderlich ist und selbst der Standardwert nicht bedeutet, dass das Schlüsselwort nicht vorhanden ist.
Matthijn

4
Das ist falsch. Das Schlüsselwort existiert. Diese Antwort ist irreführend, und ich würde empfehlen, sie abzuschaffen.
Sethfri

12

atomar (Standard)

Atomic ist die Standardeinstellung: Wenn Sie nichts eingeben, ist Ihre Eigenschaft atomar. Eine atomare Eigenschaft garantiert, dass Sie beim Versuch, daraus zu lesen, einen gültigen Wert zurückerhalten. Es gibt keine Garantie dafür, wie hoch dieser Wert sein könnte, aber Sie erhalten gute Daten zurück, nicht nur Junk-Speicher. Auf diese Weise können Sie mehrere Threads oder Prozesse auf eine einzelne Variable verweisen, einen Thread lesen und einen anderen Thread schreiben. Wenn sie gleichzeitig treffen, erhält der Reader-Thread garantiert einen der beiden Werte: entweder vor der Änderung oder nach der Änderung. Was Atomic Ihnen nicht gibt, ist irgendeine Garantie dafür, welchen dieser Werte Sie erhalten könnten. Atomic wird häufig mit Thread-Sicherheit verwechselt, und das ist nicht richtig. Sie müssen Ihre Thread-Sicherheit auf andere Weise gewährleisten.

nichtatomar

Auf der anderen Seite bedeutet nicht-atomar, wie Sie wahrscheinlich erraten können, nur: "Tun Sie dieses atomare Zeug nicht." Was Sie verlieren, ist die Garantie, dass Sie immer etwas zurückbekommen. Wenn Sie versuchen, während eines Schreibvorgangs zu lesen, können Sie Mülldaten zurückerhalten. Andererseits geht es ein bisschen schneller. Da atomare Eigenschaften etwas zaubern müssen, um sicherzustellen, dass Sie einen Wert zurückerhalten, sind sie etwas langsamer. Wenn es sich um eine Eigenschaft handelt, auf die Sie häufig zugreifen, möchten Sie möglicherweise auf nichtatomar zugreifen, um sicherzustellen, dass Sie nicht mit dieser Geschwindigkeitsstrafe konfrontiert werden.

Weitere Informationen finden Sie hier: https://realm.io/news/tmi-objective-c-property-attributes/


11

Die Standardeinstellung ist atomic, dies bedeutet, dass es Sie Leistung kostet, wenn Sie die Eigenschaft verwenden, aber es ist threadsicher. Objective-C setzt eine Sperre, sodass nur der eigentliche Thread auf die Variable zugreifen kann, solange der Setter / Getter ausgeführt wird.

Beispiel mit MRC einer Eigenschaft mit einem ivar _internal:

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

Die letzten beiden sind also gleich:

@property(atomic, retain) UITextField *userName;

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

Auf der anderen Seite wird nonatomicIhrem Code nichts hinzugefügt. Es ist also nur threadsicher, wenn Sie den Sicherheitsmechanismus selbst codieren.

@property(nonatomic, retain) UITextField *userName;

Die Schlüsselwörter müssen überhaupt nicht als erstes Eigenschaftsattribut geschrieben werden.

Vergessen Sie nicht, dies bedeutet nicht, dass die Eigenschaft als Ganzes threadsicher ist. Nur der Methodenaufruf des Setzers / Getters ist. Aber wenn Sie einen Setter und danach gleichzeitig einen Getter mit 2 verschiedenen Threads verwenden, kann dieser auch kaputt gehen!


10

Bevor Sie beginnen: Sie müssen wissen, dass jedes Objekt im Speicher aus dem Speicher freigegeben werden muss, damit ein neuer Writer ausgeführt werden kann. Sie können nicht einfach auf etwas schreiben, wie Sie es auf Papier tun. Sie müssen es zuerst löschen (freigeben) und dann können Sie darauf schreiben. Wenn im Moment , dass der Lösch erfolgt (oder halb fertig) und nichts hat noch geschrieben worden (oder die Hälfte geschrieben hat) und Sie versuchen , zu lesen , könnte es sehr problematisch sein! Atomic und Nonatomic helfen Ihnen, dieses Problem auf unterschiedliche Weise zu behandeln.

Lesen Sie zuerst diese Frage und dann die Antwort von Bbum . Lesen Sie dann außerdem meine Zusammenfassung.


atomic wird IMMER garantieren

  • Wenn zwei verschiedene Personen gleichzeitig lesen und schreiben möchten, brennt Ihr Papier nicht nur! -> Ihre Anwendung wird auch unter Rennbedingungen niemals abstürzen.
  • Wenn eine Person versucht zu schreiben und nur 4 der 8 zu schreibenden Buchstaben geschrieben hat, kann in der Mitte keine gelesen werden. Das Lesen kann nur erfolgen, wenn alle 8 Buchstaben geschrieben sind -> Es wird kein Lesen (get) durchgeführt "Ein Thread, der noch schreibt", dh wenn 8 Bytes zu Bytes geschrieben werden müssen und nur 4 Bytes geschrieben werden - bis zu diesem Moment dürfen Sie nicht daraus lesen. Aber da ich sagte, dass es nicht abstürzen wird, würde es aus dem Wert eines automatisch freigegebenen Objekts lesen .
  • Wenn vor dem Schreiben Sie haben gelöscht , dass die zuvor auf Papier geschrieben und dann jemand will Sie lesen kann noch lesen. Wie? Sie lesen aus einem ähnlichen Papierkorb wie Mac OS (da der Papierkorb noch nicht zu 100% gelöscht ist ... er befindet sich in einer Schwebe) ---> Wenn ThreadA lesen soll, während ThreadB bereits die Zuweisung zum Schreiben freigegeben hat, erhalten Sie Ein Wert aus dem endgültigen vollständig geschriebenen Wert von ThreadB oder etwas aus dem Autorelease-Pool.

Aufbewahrungszählungen sind die Art und Weise, wie der Speicher in Objective-C verwaltet wird. Wenn Sie ein Objekt erstellen, hat es eine Aufbewahrungsanzahl von 1. Wenn Sie einem Objekt eine Aufbewahrungsnachricht senden, wird seine Aufbewahrungsanzahl um 1 erhöht. Wenn Sie einem Objekt eine Freigabemeldung senden, wird seine Aufbewahrungsanzahl um 1 verringert. Wenn Sie Senden Sie einem Objekt eine Autorelease-Nachricht . Die Anzahl der Aufbewahrungen wird zu einem späteren Zeitpunkt um 1 verringert. Wenn die Anzahl der Objekte eines Objekts auf 0 reduziert wird, wird die Zuordnung aufgehoben.

  • Atomic garantiert keine Thread-Sicherheit, obwohl es nützlich ist, um Thread-Sicherheit zu erreichen. Die Thread-Sicherheit hängt davon ab, wie Sie Ihren Code schreiben / aus welcher Thread-Warteschlange Sie lesen / schreiben. Es garantiert nur nicht abstürzbares Multithreading.

Was?! Unterscheiden sich Multithreading und Thread-Sicherheit ?

Ja. Multithreading bedeutet: Mehrere Threads können gemeinsam genutzte Daten gleichzeitig lesen, und wir stürzen nicht ab. Dies garantiert jedoch nicht, dass Sie nicht von einem nicht automatisch freigegebenen Wert lesen. Mit der Thread-Sicherheit wird garantiert, dass das, was Sie lesen, nicht automatisch freigegeben wird. Der Grund dafür, dass wir nicht standardmäßig alles atomar machen, ist, dass es Leistungskosten gibt und für die meisten Dinge keine Thread-Sicherheit benötigt wird. Einige Teile unseres Codes benötigen es und für diese wenigen Teile müssen wir unseren Code threadsicher unter Verwendung von Sperren, Mutex oder Synchronisation schreiben.


nonatomic

  • Da es keinen Mac OS-Papierkorb gibt, kümmert es niemanden, ob Sie immer einen Wert erhalten (<- Dies könnte möglicherweise zu einem Absturz führen), und es interessiert niemanden, ob jemand versucht, die Hälfte Ihres Schreibens zu lesen (obwohl Das Schreiben auf halbem Weg im Speicher unterscheidet sich stark vom Schreiben auf halbem Weg auf Papier. Auf dem Speicher kann es einen verrückten, dummen Wert von früher geben, während auf dem Papier nur die Hälfte des Geschriebenen angezeigt wird.) -> Garantiert nicht, dass es nicht abstürzt, weil Es wird kein Autorelease-Mechanismus verwendet.
  • Garantiert nicht das Lesen der vollständigen geschriebenen Werte!
  • Ist schneller als atomar

Insgesamt unterscheiden sie sich in 2 Aspekten:

  • Absturz oder nicht, weil ein Autorelease-Pool vorhanden ist oder nicht.

  • Erlaubt, mitten in einem 'noch nicht abgeschlossenen Schreib- oder leeren Wert' gelesen zu werden oder nicht zuzulassen und nur zu lesen, wenn der Wert vollständig geschrieben ist.


9

Wenn Sie Ihre Eigenschaft in Multithread-Code verwenden, können Sie den Unterschied zwischen nichtatomaren und atomaren Attributen erkennen. Nichtatomar ist schneller als atomar und atomar ist threadsicher, nicht nichtatomar.

Vijayendra Tripathi hat bereits ein Beispiel für eine Multithread-Umgebung gegeben.


9
  • -Atom bedeutet, dass nur ein Thread auf die Variable zugreift (statischer Typ).
  • -Atomic ist threadsicher.
  • -aber es ist langsam in der Leistung

Wie zu erklären:

Da Atomic standardmäßig so ist,

@property (retain) NSString *name;

UND in der Implementierungsdatei

self.name = @"sourov";

Angenommen, eine Aufgabe, die sich auf drei Eigenschaften bezieht, ist

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

Alle Eigenschaften arbeiten parallel (wie asynchron).

Wenn Sie "Name" von Thread A aufrufen ,

Und

Zur gleichen Zeit, wenn Sie anrufen

[self setName:@"Datta"]

von Faden B ,

Wenn die Eigenschaft * name nicht atomar ist, dann

  • Es wird der Wert "Datta" für A zurückgegeben
  • Es wird der Wert "Datta" für B zurückgegeben

Das ist der Grund, warum nicht atomar als Thread unsicher bezeichnet wird. Aufgrund der parallelen Ausführung ist die Leistung jedoch schnell

Wenn die Eigenschaft * name atomar ist

  • Es wird den Wert "Sourov" für A sicherstellen
  • Dann wird der Wert "Datta" für B zurückgegeben

Aus diesem Grund wird Atomic als Thread-sicher und als Read-Write-Safe bezeichnet

Eine solche Situationsoperation wird seriell ausgeführt. Und langsam in der Leistung

- Nichtatomar bedeutet, dass mehrere Threads auf die Variable zugreifen (dynamischer Typ).

- Nichtatomar ist Thread unsicher.

- aber es ist schnell in der Leistung

-Nonatomic ist KEIN Standardverhalten. Wir müssen dem Eigenschaftsattribut ein nichtatomares Schlüsselwort hinzufügen.

Für In Swift Bestätigen, dass Swift-Eigenschaften im ObjC-Sinne nichtatomar sind. Ein Grund ist, dass Sie darüber nachdenken, ob die Atomizität pro Eigenschaft für Ihre Bedürfnisse ausreicht.

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

Weitere Informationen finden Sie auf der Website http://rdcworld-iphone.blogspot.in/2012/12/variable-property-attributes-or.html


4
Wie viele, viele, viele maaaaany andere gesagt haben, atomicist NICHT threadsicher! Es ist widerstandsfähiger gegen Fadenprobleme, aber nicht fadensicher. Es stellt nur sicher, dass Sie einen ganzen Wert erhalten, auch bekannt als "korrekter" Wert (Binärebene), aber es stellt keinesfalls sicher, dass es sich um den aktuellen und "korrekten" Wert für Ihre Geschäftslogik handelt (es kann sich um einen vergangenen Wert handeln und nach Ihrer Logik ungültig).
Alejandro Iván

6

Atomizität atomar (Standard)

Atomic ist die Standardeinstellung: Wenn Sie nichts eingeben, ist Ihre Eigenschaft atomar. Eine atomare Eigenschaft garantiert, dass Sie beim Versuch, daraus zu lesen, einen gültigen Wert zurückerhalten. Es gibt keine Garantie dafür, wie hoch dieser Wert sein könnte, aber Sie erhalten gute Daten zurück, nicht nur Junk-Speicher. Auf diese Weise können Sie mehrere Threads oder Prozesse auf eine einzelne Variable verweisen, einen Thread lesen und einen anderen Thread schreiben. Wenn sie gleichzeitig treffen, erhält der Reader-Thread garantiert einen der beiden Werte: entweder vor der Änderung oder nach der Änderung. Was Atomic Ihnen nicht gibt, ist irgendeine Garantie dafür, welchen dieser Werte Sie erhalten könnten. Atomic wird häufig mit Thread-Sicherheit verwechselt, und das ist nicht richtig. Sie müssen Ihre Thread-Sicherheit auf andere Weise gewährleisten.

nichtatomar

Auf der anderen Seite bedeutet nicht-atomar, wie Sie wahrscheinlich erraten können, nur: "Tun Sie dieses atomare Zeug nicht." Was Sie verlieren, ist die Garantie, dass Sie immer etwas zurückbekommen. Wenn Sie versuchen, während eines Schreibvorgangs zu lesen, können Sie Mülldaten zurückerhalten. Andererseits geht es ein bisschen schneller. Da atomare Eigenschaften etwas zaubern müssen, um sicherzustellen, dass Sie einen Wert zurückerhalten, sind sie etwas langsamer. Wenn es sich um eine Eigenschaft handelt, auf die Sie häufig zugreifen, möchten Sie möglicherweise auf nichtatomar zugreifen, um sicherzustellen, dass Sie diese Geschwindigkeitsstrafe nicht erleiden. Zugriff

Mit freundlicher Genehmigung von https://academy.realm.io/posts/tmi-objective-c-property-attributes/

Atomicity-Eigenschaftsattribute (atomar und nichtatomar) werden in der entsprechenden Swift-Eigenschaftsdeklaration nicht berücksichtigt, aber die Atomicity-Garantien der Objective-C-Implementierung gelten weiterhin, wenn von Swift aus auf die importierte Eigenschaft zugegriffen wird.

Wenn Sie also in Objective-C eine atomare Eigenschaft definieren, bleibt diese bei Verwendung durch Swift atomar.

Mit freundlicher Genehmigung von https://medium.com/@YogevSitton/atomic-vs-non-atomic-properties-crash-course-d11c23f4366c


5

Die atomare Eigenschaft stellt sicher, dass ein vollständig initialisierter Wert beibehalten wird, unabhängig davon, wie viele Threads Getter & Setter ausführen.

Die nichtatomare Eigenschaft gibt an, dass synthetisierte Accessoren einfach einen Wert direkt festlegen oder zurückgeben, ohne dass garantiert werden kann, was passiert, wenn von verschiedenen Threads gleichzeitig auf denselben Wert zugegriffen wird.


3

Atomic bedeutet, dass jeweils nur ein Thread auf die Variable zugreifen kann (statischer Typ). Atomic ist threadsicher, aber langsam.

Nichtatomar bedeutet, dass mehrere Threads gleichzeitig auf die Variable zugreifen können (dynamischer Typ). Nichtatomar ist threadsicher, aber schnell.


1

Wenn Sie Atomic verwenden, bedeutet dies, dass der Thread sicher und schreibgeschützt ist. Wenn Sie nichtatomar verwenden, bedeutet dies, dass mehrere Threads auf die Variable zugreifen und Thread-unsicher sind. Es wird jedoch schnell ausgeführt und es werden Lese- und Schreibvorgänge ausgeführt. Dies ist ein dynamischer Typ.


1

Die Wahrheit ist, dass sie Spin Lock verwenden, um atomare Eigenschaften zu implementieren. Der Code wie folgt:

 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

Lassen Sie uns die Mutex-Sperre verstehen, um die gesamte Verwirrung zu vereinfachen.

Die Mutex-Sperre sperrt gemäß dem Namen die Veränderlichkeit des Objekts. Wenn also eine Klasse auf das Objekt zugreift, kann keine andere Klasse auf dasselbe Objekt zugreifen.

@sychroniseStellt in iOS auch die Mutex-Sperre bereit. Jetzt wird sie im FIFO-Modus bereitgestellt und stellt sicher, dass der Fluss nicht von zwei Klassen beeinflusst wird, die dieselbe Instanz gemeinsam nutzen. Wenn sich die Aufgabe jedoch im Hauptthread befindet, vermeiden Sie den Zugriff auf Objekte mithilfe atomarer Eigenschaften, da dies Ihre Benutzeroberfläche enthalten und die Leistung beeinträchtigen kann.


-1

Atomic: Stellen Sie die Thread-Sicherheit sicher, indem Sie den Thread mit NSLOCK sperren.

Nicht atomar: Gewährleistet keine Gewindesicherheit, da kein Gewindesperrmechanismus vorhanden ist.


-1

Atomare Eigenschaften : - Wenn eine Variable, der eine atomare Eigenschaft zugewiesen wurde, dh nur einen Threadzugriff hat und threadsicher und in Bezug auf die Leistung gut ist, ein Standardverhalten aufweist.

Nichtatomare Eigenschaften : - Wenn eine Variable, der eine atomare Eigenschaft zugewiesen wurde, dh über einen Multi-Thread-Zugriff verfügt und nicht threadsicher und in der Leistungsperspektive langsam ist, ein Standardverhalten aufweist und zwei verschiedene Threads gleichzeitig auf eine Variable zugreifen möchten es wird unerwartete Ergebnisse geben.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.