Was bedeuten atomic
und nonatomic
in Eigenschaftsdeklarationen?
@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;
Was ist der betriebliche Unterschied zwischen diesen drei?
Die letzten beiden sind identisch. "atomar" ist das Standardverhalten (beachten Sie, dass es sich eigentlich nicht um ein Keyword handelt. es wird nur durch das Fehlen von - nonatomic
angegebenatomic
wurde in den letzten Versionen von llvm/clang als Schlüsselwort hinzugefügt.
Wenn Sie davon ausgehen, dass Sie die Implementierungen der Methode @ synthetisieren, ändert atomarer und nicht atomarer Code den generierten Code. Wenn Sie Ihre eigenen Setter/Getter schreiben, sind atomare/nichtatomare/behalten/zuweisen/kopieren nur Ratschläge. (Hinweis: @synthesize ist jetzt das Standardverhalten in neueren Versionen von LLVM. Außerdem müssen Instanzvariablen nicht deklariert werden; sie werden ebenfalls automatisch synthetisiert und mit einem _
versehen, um einen versehentlichen direkten Zugriff zu verhindern.).
Mit "atomic" stellt der synthetisierte Setter/Getter sicher, dass ein ganze - Wert immer vom Getter zurückgegeben oder vom Setter gesetzt wird, unabhängig von der Setteraktivität in einem anderen Thread. Wenn sich Thread A in der Mitte des Getters befindet, während Thread B den Setter aufruft, wird ein tatsächlich realisierbarer Wert - am wahrscheinlichsten ein automatisch freigegebenes Objekt - an den Aufrufer in A zurückgegeben.
In nonatomic
werden solche Garantien nicht gegeben. nonatomic
ist also wesentlich schneller als "atomar".
Was "atomar" tut nicht macht, ist keine Garantie für die Gewindesicherheit. Wenn Thread A den Getter gleichzeitig aufruft, während Thread B und C den Setter mit unterschiedlichen Werten aufrufen, kann Thread A einen der drei Werte zurückgeben - den Wert, der vor dem Aufruf eines Setters oder eines der Werte, die in den Setter übergeben werden, zurückgegeben wird 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 Multithreading-Programmierung - wird auf andere Weise erreicht.
Hinzufügen zu diesem:
atomicity
einer einzelnen Eigenschaft kann auch keine Thread-Sicherheit gewährleisten, 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 umbenennen, indem Sie setFirstName:
und dann setLastName:
aufrufen. In der Zwischenzeit kann Thread B fullName
zwischen den beiden Aufrufen von Thread A aufrufen und erhält den neuen Vornamen, der mit dem alten Nachnamen gekoppelt ist.
Um dies anzugehen, benötigen Sie ein Transaktionsmodell. Das heißt eine andere Art der Synchronisierung und/oder des Ausschlusses, die den Zugriff auf fullName
ausschließen, während die abhängigen Eigenschaften aktualisiert werden.
Dies wird in Apples documentation erklärt. Nachfolgend finden Sie einige Beispiele dafür, was tatsächlich passiert. Beachten Sie, dass es kein Schlüsselwort "atomic" gibt. Wenn Sie nicht "nonatomic" angeben, ist die Eigenschaft atomar. Wenn Sie jedoch "atomic" explizit angeben, wird ein Fehler ausgegeben.
//@property(nonatomic, retain) UITextField *userName;
//Generates roughly
- (UITextField *) userName {
return userName;
}
- (void) setUserName:(UITextField *)userName_ {
[userName_ retain];
[userName release];
userName = userName_;
}
Nun 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 eine Sperre einnehmen, um die Thread-Sicherheit zu gewährleisten, und die Referenzzählung für das Objekt (und die Autorelease-Zählung zum Ausgleich) so abwägen, dass das Objekt garantiert für den Aufrufer existiert, andernfalls dort ist eine potenzielle Race-Bedingung, wenn ein anderer Thread den Wert festlegt, wodurch der ref count auf 0 fällt.
Es gibt tatsächlich eine große Anzahl verschiedener Varianten, wie diese Dinge funktionieren, abhängig davon, ob es sich bei den Eigenschaften um skalare Werte oder Objekte handelt und wie die Eigenschaften keep, copy, readonly, nonatomic usw. interagieren. Im Allgemeinen wissen die Eigenschaftssynthesizer, wie sie für alle Kombinationen das "Richtige" tun.
Der beste Weg, den Unterschied zu verstehen, ist das folgende Beispiel.
Angenommen, es gibt eine atomare Zeichenfolge-Eigenschaft namens "Name". Wenn Sie [self setName:@"A"]
von Thread A aufrufen, [self setName:@"B"]
von Thread B aufrufen und [self name]
von Thread C aufrufen, werden alle Operationen für verschiedene Threads seriell ausgeführt, dh, wenn ein Thread vorhanden ist Wenn Sie einen Setter oder Getter ausführen, warten andere Threads.
Dies macht die Eigenschaft "name" Lese-/Schreibschutz sicher, aber wenn ein anderer Thread, D, gleichzeitig [name release]
aufruft, kann dies zu einem Absturz führen, da hier kein Setter/Getter-Aufruf vorhanden ist. Dies bedeutet, dass ein Objekt schreibgeschützt (ATOMIC) ist, aber nicht threadsicher, da ein anderer Thread gleichzeitig beliebige Nachrichten an das Objekt senden kann. Der Entwickler sollte die Thread-Sicherheit für solche Objekte gewährleisten.
Wenn die Eigenschaft "name" nicht atomar war, werden alle Threads in obigem Beispiel - A, B, C und D gleichzeitig ausgeführt und erzeugen ein unvorhersehbares Ergebnis. Im Falle von Atomic wird entweder A, B oder C zuerst ausgeführt, D kann jedoch weiterhin parallel ausgeführt werden.
Die Syntax und die Semantik sind bereits durch andere hervorragende Antworten auf diese Frage definiert. Da Ausführung und Leistung nicht genau beschrieben werden, füge ich meine Antwort hinzu.
Was ist der funktionale Unterschied zwischen diesen 3?
Ich hatte Atom als einen Standard immer als sehr neugierig betrachtet. Auf der Abstraktionsebene arbeiten wir daran, atomare Eigenschaften für eine Klasse als Fahrzeug zu verwenden, um eine Gewindesicherheit von 100% zu erreichen. Für wirklich korrekte Multithread-Programme ist ein Eingreifen des Programmierers mit großer Wahrscheinlichkeit eine Voraussetzung. Leistungsmerkmale und Ausführung wurden bisher noch nicht detailliert beschrieben. Nachdem ich im Laufe der Jahre einige stark multithreaded-Programme geschrieben hatte, hatte ich meine Eigenschaften die ganze Zeit als nonatomic
deklariert, da Atomic für keinen Zweck sinnvoll war. Bei der Diskussion der Details atomarer und nichtatomarer Eigenschaften dieser Frage habe ich einige Profile gemacht, die auf einige merkwürdige Ergebnisse gestoßen sind.
Ausführung
OK. Als erstes möchte ich klarstellen, dass die Implementierung der Sperrung implementierungsdefiniert und abstrahiert ist. Louis verwendet @synchronized(self)
in seinem Beispiel - ich habe dies als eine allgemeine Quelle der Verwirrung gesehen. Die Implementierung führt nicht zu tatsächlich use @synchronized(self)
; Es verwendet Objektebene Spin Locks. Louis 'Illustration eignet sich gut für eine übergeordnete Illustration mit Konstrukten, mit denen wir alle vertraut sind, aber es ist wichtig zu wissen, dass @synchronized(self)
nicht verwendet wird.
Ein weiterer Unterschied besteht darin, dass atomare Eigenschaften Ihre Objekte innerhalb des Getters beibehalten/freigeben.
Leistung
Hier ist der interessante Teil: Die Leistung mit atomaren Eigenschaftszugriffen in uncontested -Fällen (z. B. Single-Threading) 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 Mehraufwands von nonatomic
verursachen. Während der Fall Contested mit 7 Threads 44-mal langsamer war für die 3-Byte-Struktur (2,2 GHz Core i7 Quad-Core, x86_64). 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 atomaren Accessoren; oder 84% der Geschwindigkeit von synthetisierten nichtatomaren Accessoren.
Objekte in umstrittenen Fällen können auch das 50-fache überschreiten.
Aufgrund der Anzahl von Optimierungen und Variationen bei Implementierungen ist es ziemlich schwierig, die Auswirkungen auf die reale Welt in diesen Kontexten zu messen. Sie hören oft etwas wie "Vertrauen Sie ihr, wenn Sie kein Profil haben und feststellen, dass es ein Problem ist". Aufgrund des Abstraktionsniveaus ist es tatsächlich ziemlich schwierig, die tatsächlichen Auswirkungen zu messen. Das Ablesen der tatsächlichen Kosten von Profilen kann sehr zeitaufwändig sein und aufgrund von Abstraktionen ziemlich ungenau sein. ARC vs. MRC kann ebenfalls einen großen Unterschied machen.
Lassen Sie uns also einen Schritt zurückgehen, nicht auf die Implementierung von Eigenschaftszugriffen fokussieren. Wir schließen die üblichen Verdächtigen wie objc_msgSend
ein und untersuchen einige realistische Ergebnisse auf hoher Ebene für viele Aufrufe eines NSString
getter in unbestritten Fälle (Werte in Sekunden):
Wie Sie wahrscheinlich bereits vermutet haben, leistet die Referenzzähleraktivität/-zyklus einen bedeutenden Beitrag bei Atomic und unter ARC. Sie würden auch größere Unterschiede in umstrittenen Fällen feststellen.
Obwohl ich sehr auf die Leistung achte, sage ich trotzdem Semantics First!. Mittlerweile hat Leistung bei vielen Projekten eine geringe Priorität. Die Ausführungsdetails und -kosten der von Ihnen verwendeten Technologien zu kennen, schadet jedoch nicht. Sie sollten die richtige Technologie für Ihre Bedürfnisse, Zwecke und Fähigkeiten verwenden. Hoffentlich ersparen Sie sich damit einige Stunden Vergleiche und helfen Ihnen beim Treffen Ihrer Programme, eine fundiertere Entscheidung zu treffen.
Atomic = Gewindesicherheit
Nicht-atomar = Keine Gewindesicherheit
Instanzvariablen sind threadsicher, wenn sie sich beim Zugriff von mehreren Threads korrekt verhalten, unabhängig von der Planung oder Verschachtelung der Ausführung dieser Threads durch die Laufzeitumgebung und ohne zusätzliche Synchronisation oder sonstige Koordination seitens des aufrufenden Codes.
Wenn ein Thread den Wert der Instanz ändert, ist der geänderte Wert für alle Threads verfügbar, und nur ein Thread kann den Wert gleichzeitig ändern.
atomic
verwenden:wenn auf die Instanzvariable in einer Multithread-Umgebung zugegriffen wird.
atomic
:Nicht so schnell wie nonatomic
, da nonatomic
von der Laufzeit aus keine Watchdog-Arbeit erfordert.
nonatomic
verwenden:Wenn die Instanzvariable nicht von mehreren Threads geändert wird, können Sie sie verwenden. Es verbessert die Leistung.
Ich fand eine ziemlich gute Erklärung für atomare und nichtatomare Eigenschaften hier . Hier ist ein relevanter Text aus dem gleichen:
'atomar' bedeutet, dass es nicht zerlegt werden kann. Unter OS/Programmierung versteht man einen atomaren Funktionsaufruf, der nicht unterbrochen werden kann. Die gesamte Funktion muss ausgeführt werden und darf nicht durch die normale Kontextumschaltung der OS aus der CPU ausgelagert werden, bis sie abgeschlossen ist. Nur für den Fall, dass Sie nicht wussten: Da die CPU jeweils nur eine Aufgabe ausführen kann, dreht das Betriebssystem den Zugriff auf die CPU in kleinen Zeitabschnitten auf alle laufenden Prozesse, um die Illusion zu erzeugen von Multitasking. Der CPU-Scheduler kann (und tut) einen Prozess zu jedem Zeitpunkt seiner Ausführung unterbrechen - auch während eines 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 also "atomar" ausgeführt werden, dh, jede Aktualisierungsaktion muss vollständig abgeschlossen sein, bevor ein anderer Prozess auf den Server übertragen werden kann ZENTRALPROZESSOR.
Ich würde also vermuten, dass atomar in diesem Fall bedeutet, dass die Attribut-Reader-Methoden nicht unterbrochen werden können. Dies bedeutet, dass die von der Methode gelesenen Variablen ihren Wert nicht auf halbem Weg ändern können, da ein anderer Thread/Aufruf/eine andere Funktion abgerufen wird auf die CPU getauscht.
Da die Variablen atomic
nicht unterbrochen werden können, ist der von ihnen enthaltene Wert zu jedem Zeitpunkt (thread-lock) garantiert unbeschädigt . Wenn Sie jedoch sicherstellen, dass diese Thread-Sperre aktiviert ist, wird der Zugriff auf sie langsamer. non-atomic
-Variablen geben dagegen keine Garantie, bieten aber den Luxus eines schnelleren Zugriffs. Um es zusammenzufassen, fahren Sie mit non-atomic
fort, wenn Sie wissen, dass nicht mehrere Threads gleichzeitig auf Ihre Variablen zugreifen können, und beschleunigen Sie die Schritte.
Nachdem ich so viele Artikel gelesen und Stack Overflow veröffentlicht und Demo-Anwendungen zur Prüfung der Attributeigenschaften von Variablen erstellt hatte, entschied ich mich, alle Attributinformationen zusammenzustellen:
atomic
/ Standardeinstellungnonatomic
strong = retain
// Standardeinstellungweak = unsafe_unretained
retain
assign
// Standardeinstellungunsafe_unretained
copy
readonly
readwrite
// StandardeinstellungIm Artikel _/Variableneigenschaftsattribute oder -modifizierer in iOS finden Sie alle oben genannten Attribute, und das wird Ihnen definitiv helfen.
atomic
atomic
bedeutet, dass nur ein Thread auf die Variable zugreift (statischer Typ).atomic
ist threadsicher.atomic
ist das StandardverhaltenBeispiel:
@property (retain) NSString *name;
@synthesize name;
nonatomic
nonatomic
bedeutet, dass mehrere Threads auf die Variable zugreifen (dynamischer Typ).nonatomic
ist Thread-unsicher.nonatomic
ist NICHT das Standardverhalten. Wir müssen das Schlüsselwort nonatomic
im Eigenschaftsattribut hinzufügen.Beispiel:
@property (nonatomic, retain) NSString *name;
@synthesize name;
Atomic garantiert, dass der Zugriff auf die Immobilie atomar erfolgt. Z.B. Es werden immer vollständig initialisierte Objekte zurückgegeben. Jedes Get/Set 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 auftritt, können Sie sehen, warum die Ergebnisse nicht hübsch 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 macht es bei Multithreading zur besten Wahl.
Nachteile: Leistungstreffer, macht die Ausführung etwas langsamer
Im Gegensatz zu Atomic kann nicht jedes Mal eine vollständig initialisierte Objektrückgabe sichergestellt werden.
Pros: Extrem schnelle Ausführung.
Nachteile: Chancen für den Müllwert bei Multithreading.
Die einfachste Antwort zuerst: Es gibt keinen Unterschied zwischen Ihren zweiten beiden Beispielen. Standardmäßig sind Eigenschaftszugriffe atomar.
Atomare Accessoren in einer Umgebung, in der keine Abfälle gesammelt wurden (d. H. Bei Verwendung von keep/release/autorelease), verwenden eine Sperre, um sicherzustellen, dass ein anderer Thread die korrekte Einstellung/das korrekte Abrufen des Werts nicht beeinträchtigt.
Weitere Informationen und weitere Hinweise zum Erstellen von Multithread-Apps finden Sie im Abschnitt " Leistung und Threading " der Dokumentation Objective-C 2.0 von Apple.
Atomic bedeutet, dass nur ein Thread auf die Variable zugreift (statischer Typ). Atomic ist Thread-sicher, aber langsam.
Nichtatomisch bedeutet, dass mehrere Threads auf die Variable zugreifen (dynamischer Typ). Nichtatomisch ist Thread-unsicher, aber es ist schnell.
Atomic ist thread safe, es ist slow und wells versichert (nicht garantiert), dass nur der gesperrte Wert angegeben wird, unabhängig davon, wie viele Threads über dieselbe Zone zugreifen. Wenn Sie atomar verwenden, wird ein in diese Funktion geschriebener Code zu einem Teil des kritischen Abschnitts, zu dem jeweils nur ein Thread ausgeführt werden kann.
Es gewährleistet nur die Gewindesicherheit; es garantiert das nicht. Was ich damit meine, ist, dass Sie einen erfahrenen Fahrer für Ihr Auto anstellen, aber es garantiert nicht, dass das Auto keinen Unfall hat. Die Wahrscheinlichkeit bleibt jedoch die geringste.
Atomic - es kann nicht zerlegt werden, daher wird das Ergebnis erwartet. Bei nonatomic - Wenn ein anderer Thread auf die Speicherzone zugreift, kann er diese ändern, sodass das Ergebnis unerwartet ist.
Code Talk:
Atomischer Get-Getter und Setter des Property-Threads sicher. zum Beispiel, wenn Sie geschrieben haben:
self.myProperty = value;
ist threadsicher.
[myArray addObject:@"Abc"]
ist NICHT threadsicher.
Es gibt kein solches Schlüsselwort "atomar"
@property(atomic, retain) UITextField *userName;
Wir können das obige gerne verwenden
@property(retain) UITextField *userName;
Siehe Stapelüberlauf-Frage Ich bekomme Probleme, wenn ich @property (atomic, keep) NSString * myString verwende.
Das default ist atomic
, das heißt, es kostet Sie Leistung, wenn Sie die Eigenschaft verwenden, aber es ist threadsicher. Was Objective-C tut, ist eine Sperre, sodass nur der tatsächliche 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 fügt nonatomic
nichts zu Ihrem Code hinzu. Es ist also nur fadensicher, wenn Sie den Sicherheitsmechanismus selbst codieren.
@property(nonatomic, retain) UITextField *userName;
Die Schlüsselwörter müssen überhaupt nicht als erstes Eigenschaftsattribut geschrieben werden.
Vergiss nicht, das bedeutet nicht, dass die Eigenschaft insgesamt Thread-sicher ist. Nur der Methodenaufruf des Setter/Getters ist. Wenn Sie jedoch einen Setter und danach einen Getter gleichzeitig mit 2 verschiedenen Threads verwenden, könnte dieser ebenfalls beschädigt werden!
atomar (Standard)
Atomic ist die Standardeinstellung: Wenn Sie nichts eingeben, lautet Ihre Eigenschaft atomar. Eine atomare Eigenschaft ist garantiert, wenn Sie versuchen, aus .__ zu lesen. Dann erhalten Sie einen gültigen Wert zurück. Es gibt keine Garantien was der Wert sein könnte, aber Sie erhalten gute Daten zurück, nicht nur Junk-Speicher. Sie können dies tun, wenn Sie mehrere Threads oder mehrere Prozesse, die auf eine einzige Variable zeigen, eine Thread kann lesen und ein anderer Thread kann schreiben. Wenn sie gleichzeitig schlagen Zu diesem Zeitpunkt erhält der Reader-Thread garantiert einen der beiden Werte: entweder vor der Änderung oder nach der Änderung. Was atomar nicht tut Ihnen geben Sie eine Garantie dafür, welche dieser Werte Sie haben vielleicht bekommen. Atomic wird in der Regel mit Thread-sicherem .__ verwechselt. und das stimmt nicht. Sie müssen Ihre Thread-Sicherheit gewährleisten andere Möglichkeiten. Atomic garantiert jedoch, dass .__, wenn Sie versuchen zu lesen. Sie erhalten einen Wert zurück.
nichtatomisch
Auf der anderen Seite bedeutet nicht-atomar, wie Sie wahrscheinlich vermuten können, nur „Mach das nicht atomare Sachen.“ Was du verlierst, ist die Garantie, dass du Immer etwas zurückbekommen. Wenn Sie versuchen, mitten in einem .__ zu lesen. schreiben, könnten Sie Mülldaten zurückbekommen. Andererseits gehen Sie. ein bisschen schneller. Weil atomare Eigenschaften etwas Magisches bewirken müssen Um zu garantieren, dass Sie einen Wert zurückbekommen, sind sie etwas langsamer. Ob Es ist eine Eigenschaft, auf die Sie häufig zugreifen, Sie möchten .__ löschen. auf nichtatomisch, um sicherzustellen, dass Sie diese Geschwindigkeit nicht erreichen Strafe.
Mehr dazu hier: https://realm.io/news/tmi-objective-c-property-attributes/
Bevor Sie beginnen: Sie müssen wissen, dass jedes Objekt im 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 in dem Moment, in dem der Löschvorgang abgeschlossen ist (oder die Hälfte abgeschlossen ist) und noch nichts geschrieben wurde (oder die Hälfte geschrieben wurde) und Sie versuchen, es lesen könnten sei sehr problematisch! Atomic und Nonatomic helfen Ihnen, dieses Problem auf verschiedene Arten zu behandeln.
Lesen Sie zuerst this question und dann Bbums Antwort . Lesen Sie außerdem dann meine Zusammenfassung.
atomic
garantiert IMMER
Beibehaltungszähler sind die Art und Weise, wie Speicher in Objective-C verwaltet wird. Wenn Sie ein Objekt erstellen, hat es eine Aufbewahrungszahl von 1. Wenn Sie einem Objekt eine Aufbewahrungsnachricht senden, wird die Aufbewahrungszahl um 1 erhöht. Wenn Sie einem Objekt eine Freigabemeldung senden, wird die Aufbewahrungszahl um 1 verringert Senden Sie einem Objekt eine Autorelease-Nachricht , deren Anzahl der Aufbewahrungen zu einem späteren Zeitpunkt um 1 verringert wird. Wenn der Aufbewahrungszähler eines Objekts auf 0 reduziert wird, wird die Zuordnung aufgehoben.
Was ?! Sind Multithreading und Thread-Sicherheit unterschiedlich?
Ja. Multithreading bedeutet: Mehrere Threads können ein gemeinsam genutztes Datenelement gleichzeitig lesen und wir werden nicht abstürzen, es kann jedoch nicht garantiert werden, 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, warum wir nicht standardmäßig alles atomar machen, ist, dass es Leistungskosten gibt und für die meisten Dinge keine wirkliche Threadsicherheit erforderlich ist. Einige Teile unseres Codes benötigen diesen Code, und für diese wenigen Teile müssen wir unseren Code threadsicher mithilfe von Sperren, Mutex oder Synchronisierung schreiben.
nonatomic
Insgesamt unterscheiden sie sich in 2 Aspekten:
Absturz oder nicht aufgrund eines Autorelease-Pools.
Das Lesen direkt in der Mitte eines 'noch nicht beendeten Schreibens oder leeren Werts' erlauben oder nicht erlauben und nur lesen, wenn der Wert vollständig geschrieben ist.
Wenn Sie Ihre Eigenschaft in Multithread-Code verwenden, können Sie den Unterschied zwischen nichtatomaren und atomaren Attributen erkennen. Nonatomic ist schneller als atomar und atomar ist fadensicher und nicht atomar.
Vijayendra Tripathi hat bereits ein Beispiel für eine Multithread-Umgebung gegeben.
Wie erkläre ich:
Da Atom standardmäßig 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 (asynchron).
Wenn Sie "Name" aus dem Thread A aufrufen,
Und
Zur gleichen Zeit, wenn Sie anrufen
[self setName:@"Datta"]
aus dem Thread B,
Now Wenn die * name -Eigenschaft nicht atomar ist, dann
Aus diesem Grund wird Nicht-Atom als Thread unsicher bezeichnet. Aufgrund der parallelen Ausführung ist die Leistung jedoch schnell.
Now If * name -Eigenschaft ist atomar
Deshalb heißt atomic threadsicher und deshalb heißt es schreibgeschützt
Eine solche Situation wird seriell durchgeführt. Und langsam in der Leistung
- Nonatomic bedeutet, dass mehrere Threads auf die Variable zugreifen (dynamischer Typ).
- Nichtatomisch ist Thread unsicher.
- aber es ist schnell in der Leistung
-Nonatomic ist NICHT Standardverhalten, wir müssen ein nichtatomisches Schlüsselwort im Eigenschaftsattribut hinzufügen.
Für In Swift Bestätigung, dass die Swift-Eigenschaften im ObjC-Sinn nicht atomar sind. Ein Grund ist, dass Sie darüber nachdenken, ob die Atomizität pro Eigenschaft für Ihre Bedürfnisse ausreichend ist.
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
Bevor Sie sich mit den Attributen von @property befassen, sollten Sie wissen, wie @property verwendet wird. @property bietet eine Möglichkeit, die Informationen zu definieren, die eine Klasse kapseln soll. Wenn Sie ein Objekt/eine Variable mit @property deklarieren, können andere Klassen auf dieses Objekt/diese Variable zugreifen, die ihre Klasse importieren. Wenn Sie ein Objekt mit @property in der Header-Datei deklarieren, müssen Sie es mit @synthesize in der Implementierungsdatei synthetisieren.
Beispiel:
.h Klasse
@interface ExampleClass : NSObject
@property (nonatomic, retain) NSString *name;
@end
.m Klasse
@implementation ExampleClass
@synthesize name;
@end
Nun synthetisiert der Compiler die Zugriffsmethoden für name.
ExampleClass *newObject=[[ExampleClass alloc]init];
NSString *name1=[newObject name]; // get 'name'
[obj setName:@“Tiger”];
Liste der Attribute von @property: atomic. nichtatomar. behalten. Kopieren. schreibgeschützt. lesen Schreiben. zuordnen. stark.
atomar: Dies ist das Standardverhalten. Wenn ein Objekt als atomar deklariert wird, ist es threadsicher. Thread-sicher bedeutet, dass zu einem Zeitpunkt nur ein Thread einer bestimmten Instanz dieser Klasse die Kontrolle über dieses Objekt haben kann.
Beispiel
@property NSString *name; //by default atomic
@property (atomic)NSString *name; // explicitly declared atomic
nichtatomar: Es ist nicht threadsicher. Mit dem Attribut "nonatomic property" können Sie festlegen, dass synthetisierte Accessoren einen Wert einfach festlegen oder direkt zurückgeben. Dabei können Sie nicht garantieren, was passiert, wenn auf denselben Wert gleichzeitig von verschiedenen Threads aus zugegriffen wird. Aus diesem Grund ist der Zugriff auf eine nichtatomare Eigenschaft schneller als auf eine atomare. @property (nonatomic)NSString *name;
beibehalten: Wird benötigt, wenn das Attribut ein Zeiger auf ein Objekt ist. Die Setter-Methode erhöht die Anzahl der Beibehaltungen des Objekts, sodass der Speicher im Autorelease-Pool belegt wird. @property (retain)NSString *name;
kopieren: Wenn Sie Kopieren verwenden, können Sie Retain nicht verwenden. Bei Verwendung der Instanz copy der Klasse wird eine eigene Kopie erstellt. Selbst wenn eine veränderbare Zeichenfolge festgelegt und anschließend geändert wird, erfasst die Instanz den Wert, den sie zum Zeitpunkt der Festlegung hat. Es werden keine Setter- und Getter-Methoden synthetisiert.
@property (copy) NSString *name;
NSMutableString *nameString = [NSMutableString stringWithString:@"Liza"];
xyzObj.name = nameString;
[nameString appendString:@"Pizza"];
readonly: Wenn Sie nicht zulassen möchten, dass die Eigenschaft über die Setter-Methode geändert wird, können Sie die Eigenschaft readonly deklarieren. @property (readonly) NSString *name;
readwrite: ist das Standardverhalten. Sie müssen das Attribut readwrite nicht explizit angeben.
@property (readwrite) NSString *name;
assign: Erzeugt einen Setter, der der Instanzvariablen den Wert direkt zuweist, anstatt ihn zu kopieren oder beizubehalten. Dies ist am besten für primitive Typen wie NSInteger und CGFloat oder Objekte geeignet, die Sie nicht direkt besitzen, z. B. Delegaten.
@property (assign) NSInteger year;
stark: ist ein Ersatz für behalten. @property (nonatomic, strong) AVPlayer *player;
unsafe_unretained: In Cocoa und Cocoa Touch gibt es einige Klassen, die noch keine schwachen Referenzen unterstützen. Sie können also keine schwachen Eigenschaften oder lokale Variablen deklarieren, um den Überblick zu behalten. Diese Klassen umfassen NSTextView, NSFont und NSColorSpace usw. Wenn Sie einen schwachen Verweis auf eine dieser Klassen verwenden müssen, müssen Sie einen unsicheren Verweis verwenden. Eine unsichere Referenz ähnelt einer schwachen Referenz, da sie das zugehörige Objekt nicht am Leben erhält, jedoch nicht auf null gesetzt wird, wenn die Zuordnung des Zielobjekts aufgehoben wird.
@property (unsafe_unretained) NSObject *unsafeProperty;
Die atomare Eigenschaft stellt sicher, dass ein vollständig initialisierter Wert beibehalten wird, unabhängig davon, wie viele Threads Getter & Setter darauf ausführen.
Die Eigenschaft "Nichtatomisch" gibt an, dass synthetisierte Zugriffsmethoden einen Wert einfach direkt festlegen oder zurückgeben. Es kann nicht garantiert werden, was passiert, wenn auf denselben Wert gleichzeitig von verschiedenen Threads zugegriffen wird.
Atomic bedeutet, dass jeweils nur ein Thread auf die Variable zugreifen kann (statischer Typ). Atomic ist Thread-sicher, aber langsam.
Nichtatomisch bedeutet, dass mehrere Threads gleichzeitig auf die Variable zugreifen können (dynamischer Typ). Nichtatomisch ist Thread-unsicher, aber es ist schnell.
Wenn Sie Atomic verwenden, bedeutet dies, dass der Thread sicher und schreibgeschützt ist. Wenn Sie nonatomic verwenden, bedeutet dies, dass mehrere Threads auf die Variable zugreifen und Thread-unsicher ist. Sie wird jedoch schnell ausgeführt und führt Lese- und Schreibvorgänge aus. Dies ist ein dynamischer Typ.
Atomic properties : - Wenn eine mit einer atomischen Eigenschaft zugewiesene Variable bedeutet, dass sie nur einen Threadzugriff hat und Thread-sicher ist und in der Leistungsperspektive gut ist, hat dies ein Standardverhalten.
Nicht-atomare Eigenschaften : - Wenn eine mit einer atomischen Eigenschaft zugewiesene Variable bedeutet, dass sie über einen Multithreadzugriff verfügt und nicht threadsicher ist und in der Leistungsperspektive langsam ist, das Standardverhalten und wenn zwei verschiedene Threads zugreifen möchten Variable zur gleichen Zeit gibt es unerwartete Ergebnisse.
Atomicity Atomic (Standard)
Atomic ist die Standardeinstellung: Wenn Sie nichts eingeben, ist Ihre Eigenschaft atomar. Es wird garantiert, dass eine atomare Eigenschaft einen gültigen Wert zurückgibt, wenn Sie versuchen, daraus zu lesen. Es gibt keine Garantie dafür, was dieser Wert sein könnte, aber Sie erhalten gute Daten zurück, nicht nur Junk-Speicher. Wenn Sie über mehrere Threads oder mehrere Prozesse verfügen, die auf eine einzige Variable zeigen, kann ein Thread lesen und ein anderer Thread schreiben. Wenn sie gleichzeitig treffen, erhält der Leser-Thread garantiert einen der beiden Werte: entweder vor der Änderung oder nach der Änderung. Was atomar Ihnen nicht gibt, ist eine Garantie dafür, welche dieser Werte Sie erhalten könnten. Atomic wird im Allgemeinen mit Thread-sicher verwechselt, und das ist nicht richtig. Sie müssen Ihre Threadsicherheit auf andere Weise garantieren. Atomic garantiert jedoch, dass Sie beim Lesen wieder einen Wert erhalten.
nichtatomisch
Auf der anderen Seite bedeutet nicht-atomar, wie Sie wahrscheinlich vermuten können, nur: „Tun Sie nichts Atomisches.“ Was Sie verlieren, ist die Garantie, dass Sie immer etwas zurückbekommen. Wenn Sie versuchen, während eines Schreibvorgangs zu lesen, erhalten Sie möglicherweise Mülldaten zurück. Andererseits geht man ein bisschen schneller. Da atomare Eigenschaften eine gewisse Magie erfordern, 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 Nichtatomisch zurückgreifen, um sicherzustellen, dass Sie nicht diese Geschwindigkeitsstrafe einnehmen
mit freundlicher Genehmigung https://academy.realm.io/posts/tmi-objective-c-property-attributes/
Atomicity-Eigenschaftsattribute (atomar und nichtatomisch) werden in der entsprechenden Swift-Eigenschaftendeklaration nicht berücksichtigt. Die Atomitätsgarantien der Objective-C-Implementierung gelten jedoch weiterhin, wenn auf die importierte Eigenschaft über Swift zugegriffen wird.
Also - wenn Sie eine atomare Eigenschaft in Objective-C definieren, bleibt sie bei Verwendung von Swift atomar.
courtesy https://medium.com/@YogevSitton/atomic-vs-non-atomic-properties-crash-course-d11c23f4366c
Um die gesamte Verwirrung zu vereinfachen, lassen Sie uns die Mutex-Sperre verstehen.
Die Mutex-Sperre sperrt die Namensveränderlichkeit des Objekts. Wenn also auf eine Klasse auf das Objekt zugegriffen wird, kann keine andere Klasse auf dasselbe Objekt zugreifen.
In iOS stellt @sychronise
auch die Mutex-Sperre bereit. Jetzt dient sie im Modus FIFO und stellt sicher, dass der Fluss nicht von zwei Klassen beeinflusst wird, die dieselbe Instanz verwenden. Wenn sich die Task jedoch im Hauptthread befindet, vermeiden Sie den Zugriff auf Objekte mit atomaren Eigenschaften, da dies Ihre Benutzeroberfläche halten und die Leistung beeinträchtigen kann.
Atomic: Gewährleisten Sie die Thread-Sicherheit, indem Sie den Thread mit NSLOCK sperren.
Nicht atomar: Gewährleistet keine Thread-Sicherheit, da es keinen Thread-Verriegelungsmechanismus gibt.
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);
}