Quelle est la différence entre les attributs atomiques et non atomiques?


Réponses:


1761

Les deux derniers sont identiques; "atomic" est le comportement par défaut ( notez qu'il ne s'agit pas en fait d'un mot-clé; il n'est spécifié que par l'absence denonatomic - a atomicété ajouté comme mot-clé dans les versions récentes de llvm / clang).

En supposant que vous synthétisez les implémentations de la méthode, atomique ou non atomique modifie le code généré. Si vous écrivez votre propre setter / getters, atomic / nonatomic / conserver / assigner / copier sont simplement consultatifs. (Remarque: @synthesize est désormais le comportement par défaut dans les versions récentes de LLVM. Il n'est pas non plus nécessaire de déclarer les variables d'instance; elles seront également synthétisées automatiquement et auront un _préfixe à leur nom pour empêcher tout accès direct accidentel).

Avec "atomic", le setter / getter synthétisé s'assurera qu'une valeur entière est toujours retournée par le getter ou définie par le setter, quelle que soit l'activité du setter sur tout autre thread. Autrement dit, si le thread A se trouve au milieu du getter pendant que le thread B appelle le setter, une valeur viable réelle - un objet libéré automatiquement, très probablement - sera retournée à l'appelant en A.

En nonatomic, aucune garantie de ce type n'est offerte. Ainsi, nonatomicest considérablement plus rapide que "atomique".

Ce que "atomic" ne fait pas , c'est de garantir la sécurité des threads. Si le thread A appelle le getter simultanément avec les threads B et C appelant le setter avec des valeurs différentes, le thread A peut obtenir n'importe laquelle des trois valeurs renvoyées - celle qui précède l'appel des setters ou l'une des valeurs transmises aux setters en B et C. De même, l'objet peut se retrouver avec la valeur de B ou C, aucun moyen de le dire.

Garantir l'intégrité des données - l'un des principaux défis de la programmation multithread - est obtenu par d'autres moyens.

Ajoutant à cela:

atomicity d'une seule propriété ne peut pas non plus garantir la sécurité des threads lorsque plusieurs propriétés dépendantes sont en jeu.

Considérer:

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

Dans ce cas, le thread A pourrait renommer l'objet en appelant setFirstName:puis en appelant setLastName:. En attendant, le thread B peut appeler fullNameentre les deux appels du thread A et recevra le nouveau prénom couplé avec l'ancien nom de famille.

Pour résoudre ce problème, vous avez besoin d'un modèle transactionnel . C'est-à-dire un autre type de synchronisation et / ou d'exclusion qui permet d'exclure l'accès fullNamependant la mise à jour des propriétés dépendantes.


21
Étant donné que tout code thread-safe fera son propre verrouillage, etc., quand voudriez-vous utiliser des accesseurs de propriétés atomiques? J'ai du mal à trouver un bon exemple.
Daniel Dickison

8
@bbum est logique. J'aime votre commentaire à une autre réponse que la sécurité des threads est plus une préoccupation au niveau du modèle. À partir d'une définition de sécurité des threads IBM: ibm.co/yTEbjY "Si une classe est correctement implémentée, ce qui est une autre façon de dire qu'elle est conforme à sa spécification, aucune séquence d'opérations (lecture ou écriture de champs publics et appels à des méthodes publiques) sur les objets de cette classe doit pouvoir mettre l'objet dans un état invalide, observer que l'objet est dans un état invalide, ou violer l'un des invariants, conditions préalables ou postconditions de la classe. "
Ben Flynn

6
Voici un exemple similaire à celui de @StevenKramer: J'ai un @property NSArray* astronomicalEvents;qui répertorie les données que je veux afficher dans l'interface utilisateur. Lorsque l'application lance le pointeur vers un tableau vide, l'application extrait des données du Web. Une fois la demande Web terminée (dans un autre thread), l'application crée un nouveau tableau, puis définit atomiquement la propriété sur une nouvelle valeur de pointeur. Il est sûr pour les threads et je n'ai pas eu à écrire de code de verrouillage, sauf s'il me manque quelque chose. Cela me semble assez utile.
bugloaf

10
@HotLicks Un autre amusant; sur certaines architectures (je ne me souviens pas laquelle), les valeurs 64 bits passées en argument peuvent être passées moitié dans un registre et moitié sur la pile. atomicempêche les lectures de demi-valeur entre fils. (C'était un bug amusant à retrouver.)
bbum

8
@congliu Thread A renvoie un objet sans retain/autoreleasedanse. Le thread B libère l'objet. Le fil A va boom . atomicgarantit que le thread A a une référence forte (un +1 retenir le nombre) pour la valeur de retour.
bbum

360

Cela est expliqué dans la documentation d'Apple , mais voici quelques exemples de ce qui se passe réellement.

Notez qu'il n'y a pas de mot-clé "atomic", si vous ne spécifiez pas "nonatomic", alors la propriété est atomic, mais en spécifiant explicitement "atomic", vous obtiendrez une erreur.

Si vous ne spécifiez pas "non atomique", la propriété est atomique, mais vous pouvez toujours spécifier "atomique" explicitement dans les versions récentes si vous le souhaitez.

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

- (UITextField *) userName {
    return userName;
}

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

Maintenant, la variante atomique est un peu plus compliquée:

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

Fondamentalement, la version atomique doit prendre un verrou afin de garantir la sécurité du thread, et est également en train de déplacer le compte de référence sur l'objet (et le compte de libération automatique pour l'équilibrer) afin que l'objet soit garanti pour l'appelant, sinon il y a est une condition de concurrence potentielle si un autre thread définit la valeur, entraînant la baisse du nombre de références à 0.

Il existe en fait un grand nombre de variantes différentes de la façon dont ces choses fonctionnent, selon que les propriétés sont des valeurs scalaires ou des objets, et comment interagissent la conservation, la copie, la lecture seule, la non-anatomique, etc. En général, les synthétiseurs de propriétés savent comment faire la "bonne chose" pour toutes les combinaisons.


8
@Louis Gerbarg: Je pense que votre version du setter (nonatomique, conserver) ne fonctionnera pas correctement si vous essayez d'affecter le même objet (c'est-à-dire: userName == userName_)
Florin

5
Votre code est légèrement trompeur; il n'y a aucune garantie sur quels getters / setters atomiques sont synchronisés. Surtout, @property (assign) id delegate;n'est synchronisé sur rien (iOS SDK GCC 4.2 ARM -Os), ce qui signifie qu'il y a une course entre [self.delegate delegateMethod:self];et foo.delegate = nil; self.foo = nil; [super dealloc];. Voir stackoverflow.com/questions/917884/…
tc.

@fyolnish Je ne suis pas sûr de ce que _val/ valsont, mais non, pas vraiment. Le getter pour une propriété atomic copy/ retaindoit s'assurer qu'il ne retourne pas un objet dont le refcount devient nul car le setter est appelé dans un autre thread, ce qui signifie essentiellement qu'il doit lire l'ivar, le conserver tout en s'assurant que le setter n'a pas écrasé et libéré, puis relâché automatiquement pour équilibrer la conservation. Cela signifie essentiellement que le getter et le setter doivent utiliser un verrou (si la disposition de la mémoire a été fixée, elle devrait être réalisable avec les instructions CAS2; hélas, -retainc'est un appel de méthode).
tc.

@tc Cela fait un bon bout de temps mais ce que je voulais écrire était probablement ceci: gist.github.com/fjolnir/5d96b3272c6255f6baae Mais oui, il est possible que l'ancienne valeur soit lue par un lecteur avant setFoo: renvoie, et publiée avant le le lecteur le renvoie. Mais peut-être que si le setter utilisait -autorelease au lieu de -release, cela réglerait cela.
Fjölnir

@fyolnish Malheureusement non: cela se libère automatiquement sur le thread du setter, alors qu'il doit être libéré automatiquement sur le thread du getter. Il semble également qu'il y ait une chance (mince) de manquer de pile car vous utilisez la récursivité.
tc.

170

Atomique

  • est le comportement par défaut
  • s'assurera que le processus actuel est terminé par la CPU, avant qu'un autre processus accède à la variable
  • n'est pas rapide, car il garantit que le processus est entièrement terminé

Non atomique

  • n'est PAS le comportement par défaut
  • plus rapide (pour le code synthétisé, c'est-à-dire pour les variables créées à l'aide de @property et @synthesize)
  • pas thread-safe
  • peut entraîner un comportement inattendu, lorsque deux processus différents accèdent à la même variable en même temps

137

La meilleure façon de comprendre la différence est d'utiliser l'exemple suivant.

Supposons qu'il existe une propriété de chaîne atomique appelée "nom", et si vous appelez à [self setName:@"A"]partir du thread A, appelez à [self setName:@"B"]partir du thread B et appelez à [self name]partir du thread C, alors toutes les opérations sur différents threads seront effectuées en série, ce qui signifie si un thread exécute un setter ou getter, alors d'autres threads attendront.

Cela rend la propriété "nom" en lecture / écriture sûre, mais si un autre thread, D, appelle [name release]simultanément, cette opération peut produire un crash car aucun appel setter / getter n'est impliqué ici. Ce qui signifie qu'un objet est protégé en lecture / écriture (ATOMIQUE), mais pas thread-safe car un autre thread peut envoyer simultanément tout type de messages à l'objet. Le développeur doit garantir la sécurité des threads pour ces objets.

Si la propriété "nom" n'était pas atomique, alors tous les threads de l'exemple ci-dessus - A, B, C et D s'exécuteront simultanément produisant tout résultat imprévisible. En cas d'atome, l'un de A, B ou C s'exécutera en premier, mais D peut toujours s'exécuter en parallèle.


116

La syntaxe et la sémantique sont déjà bien définies par d'autres excellentes réponses à cette question. Parce que l' exécution et les performances ne sont pas bien détaillées, j'ajouterai ma réponse.

Quelle est la différence fonctionnelle entre ces 3?

J'avais toujours considéré l'atomique comme un défaut assez curieux. Au niveau de l'abstraction où nous travaillons, l'utilisation des propriétés atomiques pour une classe comme véhicule pour atteindre une sécurité de filetage à 100% est un cas d'angle. Pour des programmes multithreads vraiment corrects, l'intervention du programmeur est presque certainement une exigence. Pendant ce temps, les caractéristiques de performance et l'exécution n'ont pas encore été détaillées en détail. Après avoir écrit des programmes lourdement multithread au fil des ans, j'avais déclaré mes propriétés comme nonatomictout le temps parce que l'atomique n'était pas sensé à quelque fin que ce soit. Au cours de la discussion des détails des propriétés atomiques et non anatomiques de cette question , j'ai fait du profilage rencontré quelques résultats curieux.

Exécution

D'accord. La première chose que je voudrais clarifier est que l'implémentation de verrouillage est définie par l'implémentation et abstraite. Louis utilise @synchronized(self)dans son exemple - j'ai vu cela comme une source commune de confusion. La mise en œuvre ne fait utiliser @synchronized(self); il utilise des verrous rotatifs au niveau de l'objet . L'illustration de Louis est bonne pour une illustration de haut niveau utilisant des constructions que nous connaissons tous, mais il est important de savoir qu'elle n'utilise pas @synchronized(self).

Une autre différence est que les propriétés atomiques conserveront / relâcheront le cycle de vos objets dans le getter.

Performance

Voici la partie intéressante: les performances utilisant des accès à la propriété atomique dans des cas non contestés (par exemple, un seul thread) peuvent être très rapides dans certains cas. Dans des cas moins qu'idéaux, l'utilisation des accès atomiques peut coûter plus de 20 fois les frais généraux de nonatomic. Alors que le cas contesté utilisant 7 threads était 44 fois plus lent pour la structure à trois octets (2,2 GHz Core i7 Quad Core, x86_64). La structure à trois octets est un exemple de propriété très lente.

Note intéressante: les accesseurs définis par l'utilisateur de la structure à trois octets étaient 52 fois plus rapides que les accesseurs atomiques synthétisés; ou 84% de la vitesse des accessoires non anatomiques synthétisés.

Les objets dans les cas contestés peuvent également dépasser 50 fois.

En raison du nombre d'optimisations et de variations dans les implémentations, il est assez difficile de mesurer les impacts réels dans ces contextes. Vous pouvez souvent entendre quelque chose comme "Faites-lui confiance, à moins que vous ne vous fassiez un profil et que vous ne trouviez que c'est un problème". En raison du niveau d'abstraction, il est en fait assez difficile de mesurer l'impact réel. Glaner les coûts réels des profils peut prendre beaucoup de temps et, en raison des abstractions, être tout à fait inexact. De plus, ARC vs MRC peut faire une grande différence.

Revenons donc en arrière, ne nous concentrant pas sur la mise en œuvre des accès à la propriété, nous inclurons les suspects habituels comme objc_msgSend, et examinons certains résultats de haut niveau du monde réel pour de nombreux appels à un NSStringgetter dans des cas non contestés (valeurs en secondes):

  • MRC | non anatomique | getters implémentés manuellement: 2
  • MRC | non anatomique | getter synthétisé: 7
  • MRC | atomique | getter synthétisé: 47
  • ARC | non anatomique | getter synthétisé: 38 (note: l'ARC ajoute le nombre de références en cyclant ici)
  • ARC | atomique | getter synthétisé: 47

Comme vous l'avez probablement deviné, l'activité / le cycle de comptage de référence est un contributeur important avec l'atomique et sous l'ARC. Vous verriez également de plus grandes différences dans les cas contestés.

Bien que je porte une attention particulière à la performance, je dis toujours la sémantique d'abord! . Pendant ce temps, la performance est une faible priorité pour de nombreux projets. Cependant, connaître les détails d'exécution et les coûts des technologies que vous utilisez ne fait certainement pas de mal. Vous devez utiliser la bonne technologie pour vos besoins, objectifs et capacités. J'espère que cela vous fera économiser quelques heures de comparaisons et vous aidera à prendre une décision plus éclairée lors de la conception de vos programmes.


MRC | atomique | getter synthétisé: 47 ARC | atomique | getter synthétisé: 47 Qu'est-ce qui les rend identiques? L'ARC ne devrait-elle pas avoir plus de frais généraux?
SDEZero

2
Donc, si les propriétés atomiques sont mauvaises, elles sont par défaut. Pour augmenter le code passe-partout?
Kunal Balani

@ LearnCocos2D je viens de tester sur 10.8.5 sur la même machine, ciblant 10.8, pour le cas unique non contesté avec un NSStringqui n'est pas immortel: -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%- les résultats sont un peu différents aujourd'hui. Je ne faisais aucune @synchronizedcomparaison. @synchronizedest sémantiquement différent, et je ne le considère pas comme un bon outil si vous avez des programmes concurrents non triviaux. si vous avez besoin de vitesse, évitez @synchronized.
juste le

avez-vous ce test en ligne quelque part? Je continue d'ajouter le mien ici: github.com/LearnCocos2D/LearnCocos2D/tree/master/…
LearnCocos2D

@ LearnCocos2D je ne les ai pas préparés pour la consommation humaine, désolé.
juste le

95

Atomic = sécurité des threads

Non atomique = Aucune sécurité de filetage

Sécurité du fil:

Les variables d'instance sont thread-safe si elles se comportent correctement lorsqu'elles sont accessibles à partir de plusieurs threads, indépendamment de la planification ou de l'entrelacement de l'exécution de ces threads par l'environnement d'exécution, et sans synchronisation supplémentaire ou autre coordination de la part du code appelant.

Dans notre contexte:

Si un thread modifie la valeur de l'instance, la valeur modifiée est disponible pour tous les threads et un seul thread peut modifier la valeur à la fois.

Où utiliser atomic:

si la variable d'instance est accessible dans un environnement multithread.

Implication de atomic:

Pas aussi vite que nonatomicparce nonatomicqu'il ne nécessite aucun travail de surveillance sur ce point à partir de l'exécution.

Où utiliser nonatomic:

Si la variable d'instance ne va pas être modifiée par plusieurs threads, vous pouvez l'utiliser. Il améliore les performances.


3
Tout ce que vous dites ici est correct, mais la dernière phrase est essentiellement "fausse", Dura, pour la programmation d'aujourd'hui. Il est vraiment inconcevable que vous vous donniez la peine d'essayer "d'améliorer les performances" de cette façon. (Je veux dire, avant d'arriver dans les années qui suivent, vous "n'utiliserez pas ARC", "n'utiliserez pas NSString parce qu'il est lent!" Et ainsi de suite.) Pour faire un exemple extrême, ce serait comme dire "équipe, ne mettez pas de commentaires dans le code, car cela nous ralentit. " Il n'y a pas de pipeline de développement réaliste où vous souhaiteriez des gains de performances théoriques (inexistants) par manque de fiabilité.
Fattie

3
@JoeBlow c'est un fait, vous pouvez le vérifier ici developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
Durai Amuthan.H

1
Durai, FWIW, ce lien contredit directement votre thèse de «Atomic = thread safety». Dans le document Apple dit explicitement: «L'atomicité des propriétés n'est pas synonyme de sécurité des threads d'un objet». Dans la pratique, l'atomique est rarement suffisant pour assurer la sécurité du fil.
Rob

69

J'ai trouvé une explication assez bien définie des propriétés atomiques et non atomiques ici . Voici un texte pertinent de la même:

«atomique» signifie qu'il ne peut pas être décomposé. En termes de système d'exploitation / programmation, un appel de fonction atomique est un appel qui ne peut pas être interrompu - la fonction entière doit être exécutée, et non échangée hors du CPU par le changement de contexte habituel du système d'exploitation jusqu'à ce qu'elle soit terminée. Juste au cas où vous ne le sauriez pas: puisque le CPU ne peut faire qu'une seule chose à la fois, le système d'exploitation fait pivoter l'accès au CPU à tous les processus en cours en peu de temps, pour donner l' illusiondu multitâche. L'ordonnanceur CPU peut (et fait) interrompre un processus à tout moment de son exécution - même en cours d'appel de fonction. Ainsi, pour des actions telles que la mise à jour de variables de compteur partagées où deux processus pourraient essayer de mettre à jour la variable en même temps, elles doivent être exécutées «atomiquement», c'est-à-dire que chaque action de mise à jour doit se terminer dans son intégralité avant que tout autre processus puisse être échangé sur le CPU.

Donc, je suppose que dans ce cas, atomique signifie que les méthodes de lecture d'attribut ne peuvent pas être interrompues - ce qui signifie en fait que la ou les variables lues par la méthode ne peuvent pas changer leur valeur à mi-chemin car un autre thread / appel / fonction obtient échangé sur le CPU.

Parce que les atomicvariables ne peuvent pas être interrompues, la valeur qu'elles contiennent à tout moment est (thread-lock) garantie d'être non corrompue , bien que, en s'assurant que ce verrou de thread rend l'accès à elles plus lent. non-atomicles variables, d'autre part, n'offrent pas une telle garantie mais offrent le luxe d'un accès plus rapide. Pour résumer, continuez non-atomiclorsque vous savez que vos variables ne seront pas accessibles simultanément par plusieurs threads et accélérez les choses.


1
Le lien est rompu. ; (
Rob

C'est le problème avec les liens :( heureusement, j'ai cité le texte pertinent dans ma réponse
tipycalFlow

67

Après avoir lu tant d'articles, publié des articles sur Stack Overflow et créé des applications de démonstration pour vérifier les attributs des propriétés variables, j'ai décidé de rassembler toutes les informations sur les attributs:

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

Dans l'article Attributs de propriété variable ou modificateurs dans iOS, vous pouvez trouver tous les attributs mentionnés ci-dessus, et cela vous aidera certainement.

  1. atomic

    • atomic signifie qu'un seul thread accède à la variable (type statique).
    • atomic est thread-safe.
    • Mais ses performances sont lentes
    • atomic est le comportement par défaut
    • Les accesseurs atomiques dans un environnement non récupéré (c.-à-d. Lors de l'utilisation de retenue / libération / libération automatique) utiliseront un verrou pour garantir qu'un autre thread n'interfère pas avec le bon réglage / obtention de la valeur.
    • Ce n'est pas vraiment un mot-clé.

    Exemple:

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

    • nonatomic signifie que plusieurs threads accèdent à la variable (type dynamique).
    • nonatomic est thread-unsafe.
    • Mais ses performances sont rapides
    • nonatomicn'est PAS un comportement par défaut. Nous devons ajouter le nonatomicmot - clé dans l'attribut de propriété.
    • Cela peut entraîner un comportement inattendu, lorsque deux processus différents (threads) accèdent à la même variable en même temps.

    Exemple:

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

Comment attribuer et renforcer / conserver les deux par défaut?
BangOperator

forte vient avec ARC, retenir était par défaut avant ARC
abdullahselek

56

Atomique:

Atomic garantit que l'accès à la propriété se fera de manière atomique. Par exemple, il retourne toujours des objets entièrement initialisés, tout get / set d'une propriété sur un thread doit se terminer avant qu'un autre puisse y accéder.

Si vous imaginez la fonction suivante se produire sur deux threads à la fois, vous pouvez voir pourquoi les résultats ne seraient pas jolis.

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

  ...
}

Avantages: Le retour d'objets entièrement initialisés à chaque fois en fait le meilleur choix en cas de multi-threading.

Inconvénients: Performance hit, rend l'exécution un peu plus lente

Non atomique:

Contrairement à Atomic, il ne garantit pas à chaque fois un retour d'objet complètement initialisé.

Avantages: exécution extrêmement rapide.

Inconvénients: Chances de valeur de déchets en cas de multi-threading.


5
Ce commentaire n'a pas beaucoup de sens. Pouvez-vous clarifier? Si vous regardez des exemples sur le site Apple, le mot-clé atomique se synchronise sur l'objet tout en mettant à jour ses propriétés.
Andrew Grant

52

Réponse la plus simple en premier: il n'y a pas de différence entre vos deux seconds exemples. Par défaut, les accesseurs de propriété sont atomiques.

Les accesseurs atomiques dans un environnement non récupéré (c.-à-d. Lors de l'utilisation de retenue / libération / libération automatique) utiliseront un verrou pour garantir qu'un autre thread n'interfère pas avec le bon réglage / obtention de la valeur.

Consultez la section " Performances et threading " de la documentation Objective-C 2.0 d'Apple pour plus d'informations et pour d'autres considérations lors de la création d'applications multi-thread.


8
Deux raisons. Tout d'abord, pour le code synthétisé, il génère plus rapidement (mais pas le code threadsafe). Deuxièmement, si vous écrivez des accesseurs clients qui ne sont pas atomiques, cela vous permet d'annoter pour tout futur utilisateur que le code n'est pas atomique lorsqu'ils lisent son interface, sans les implémenter.
Louis Gerbarg


31

Atomic signifie qu'un seul thread accède à la variable (type statique). Atomic est thread-safe, mais il est lent.

Non anatomique signifie que plusieurs threads accèdent à la variable (type dynamique). Nonatomic n'est pas sûr pour les threads, mais il est rapide.


14

Atomic est thread-safe , il est lent et il assure bien (non garanti) que seule la valeur verrouillée est fournie quel que soit le nombre de threads tentant d'accéder sur la même zone. Lorsque vous utilisez atomic, un morceau de code écrit à l'intérieur de cette fonction devient la partie de la section critique, à laquelle un seul thread peut s'exécuter à la fois.

Il assure seulement la sécurité du fil; cela ne garantit pas cela.Ce que je veux dire, c'est que vous louez un chauffeur expert pour votre voiture, mais cela ne garantit pas que la voiture ne rencontrera pas d'accident. Cependant, la probabilité reste la plus faible.

Atomique - il ne peut pas être décomposé, donc le résultat est attendu. Avec nonatomic - lorsqu'un autre thread accède à la zone mémoire, il peut le modifier, donc le résultat est inattendu.

Code Talk:

Atomic sécurise le getter et le setter du thread de propriété. par exemple si vous avez écrit:

self.myProperty = value;

est thread-safe.

[myArray addObject:@"Abc"] 

n'est PAS sûr pour les threads.


Je ne sais pas comment vient le dernier paragraphe, mais c'est tout simplement faux, il n'y a rien de tel que "copie privée".
pic du

13

Il n'y a pas un tel mot-clé "atomique"

@property(atomic, retain) UITextField *userName;

Nous pouvons utiliser ce qui précède comme

@property(retain) UITextField *userName;

Voir la question Stack Overflow Je rencontre des problèmes si j'utilise @property (atomic, retenue) NSString * myString .


10
"Il existe un tel mot-clé", le fait que le mot-clé n'est pas requis par défaut et que sa valeur par défaut ne signifie pas que le mot-clé n'existe pas.
Matthijn

4
Ceci est une erreur. Le mot-clé existe. Cette réponse est trompeuse et j'encourage à la retirer.
sethfri

12

atomique (par défaut)

Atomic est la valeur par défaut: si vous ne tapez rien, votre propriété est atomic. Une propriété atomique est garantie que si vous essayez de la lire, vous récupérerez une valeur valide. Il ne donne aucune garantie quant à cette valeur, mais vous récupérerez de bonnes données, pas seulement de la mémoire indésirable. Ce que cela vous permet de faire, c'est que si vous avez plusieurs threads ou plusieurs processus pointant vers une seule variable, un thread peut lire et un autre thread peut écrire. S'ils frappent en même temps, le thread du lecteur est garanti d'obtenir l'une des deux valeurs: soit avant la modification, soit après la modification. Ce que l'atomique ne vous donne pas, c'est une sorte de garantie quant à laquelle de ces valeurs vous pourriez obtenir. Atomic est vraiment communément confondu avec le thread-safe, et ce n'est pas correct. Vous devez garantir la sécurité de votre fil d'autres façons.

non anatomique

D'un autre côté, non atomique, comme vous pouvez probablement le deviner, signifie simplement «ne faites pas ce genre de choses atomiques». Ce que vous perdez, c'est cette garantie que vous récupérez toujours quelque chose. Si vous essayez de lire au milieu d'une écriture, vous pourriez récupérer des données inutiles. Mais d'un autre côté, vous allez un peu plus vite. Parce que les propriétés atomiques doivent faire un peu de magie pour garantir que vous récupérerez une valeur, elles sont un peu plus lentes. S'il s'agit d'une propriété à laquelle vous accédez beaucoup, vous souhaiterez peut-être passer à non anatomique pour vous assurer que vous n'encourez pas cette pénalité de vitesse.

Voir plus ici: https://realm.io/news/tmi-objective-c-property-attributes/


11

La valeur par défaut estatomic , cela signifie que cela vous coûte des performances chaque fois que vous utilisez la propriété, mais elle est thread-safe. Ce que fait Objective-C, c'est de définir un verrou, de sorte que seul le thread réel peut accéder à la variable, tant que le setter / getter est exécuté.

Exemple avec MRC d'une propriété avec un ivar _internal:

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

Ces deux derniers sont donc les mêmes:

@property(atomic, retain) UITextField *userName;

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

En revanche, nonatomicn'ajoute rien à votre code. Il n'est donc sûr que si vous codez vous-même le mécanisme de sécurité.

@property(nonatomic, retain) UITextField *userName;

Il n'est pas nécessaire que les mots clés soient écrits comme premier attribut de propriété.

N'oubliez pas, cela ne signifie pas que la propriété dans son ensemble est thread-safe. Seul l'appel de méthode du setter / getter l'est. Mais si vous utilisez un setter et ensuite un getter en même temps avec 2 threads différents, cela pourrait aussi être cassé!


10

Avant de commencer: Vous devez savoir que chaque objet en mémoire doit être désalloué de la mémoire pour qu'un nouvel écrivain se produise. Vous ne pouvez pas simplement écrire sur quelque chose comme vous le faites sur papier. Vous devez d' abord l'effacer (désallouer) et ensuite vous pouvez y écrire. Si au moment où l'effacement est fait (ou à moitié fait) et que rien n'a encore été écrit (ou à moitié écrit) et que vous essayez de le lire, cela pourrait être très problématique! Atomic et nonatomic vous aident à traiter ce problème de différentes manières.

Lisez d'abord cette question, puis lisez la réponse de Bbum . De plus, lisez mon résumé.


atomic garantira TOUJOURS

  • Si deux personnes différentes veulent lire et écrire en même temps, votre papier ne brûlera pas! -> Votre application ne plantera jamais, même en condition de course.
  • Si une personne essaie d'écrire et n'a écrit que 4 des 8 lettres à écrire, alors personne ne peut lire au milieu, la lecture ne peut être effectuée que lorsque les 8 lettres sont écrites -> Aucune lecture (get) n'aura lieu le 'un thread qui écrit toujours', c'est-à-dire s'il y a 8 octets à octets à écrire, et seulement 4 octets sont écrits - jusqu'à ce moment, vous n'êtes pas autorisé à lire à partir de celui-ci. Mais puisque j'ai dit qu'il ne planterait pas, il lirait la valeur d'un objet libéré automatiquement .
  • Si avant d' écrire, vous avez effacé ce qui était précédemment écrit sur papier et que quelqu'un veut lire, vous pouvez toujours lire. Comment? Vous lirez à partir de quelque chose de similaire à la corbeille de Mac OS (car la corbeille n'est pas encore effacée à 100% ... elle est dans les limbes) ---> Si ThreadA doit être lu alors que ThreadB a déjà été désalloué pour écrire, vous obtiendrez une valeur de la valeur finale entièrement écrite par ThreadB ou obtenir quelque chose du pool de libération automatique.

Les comptes conservés sont la manière dont la mémoire est gérée dans Objective-C. Lorsque vous créez un objet, il a un nombre de retenues de 1. Lorsque vous envoyez à un objet un message de retenue, son nombre de retenues est incrémenté de 1. Lorsque vous envoyez à un objet un message de libération, son nombre de retenues est décrémenté de 1. Lorsque vous envoyer un objet un message de libération automatique , son compte de retenue est décrémenté de 1 à un certain stade dans le futur. Si le nombre de rétention d'un objet est réduit à 0, il est désalloué.

  • Atomic ne garantit pas la sécurité des threads, bien qu'il soit utile pour garantir la sécurité des threads. La sécurité des threads est relative à la façon dont vous écrivez votre code / à partir de quelle file d'attente de threads vous lisez / écrivez. Il garantit uniquement le multithreading non-cassable.

Quoi?! Le multithreading et la sécurité des threads sont-ils différents?

Oui. Le multithreading signifie: plusieurs threads peuvent lire une donnée partagée en même temps et nous ne nous bloquerons pas, mais cela ne garantit pas que vous ne lisez pas à partir d'une valeur non publiée automatiquement. Avec la sécurité des threads, il est garanti que ce que vous lisez n'est pas publié automatiquement. La raison pour laquelle nous ne rendons pas tout atomique par défaut est qu'il y a un coût de performance et pour la plupart des choses, nous n'avons pas vraiment besoin de sécurité des threads. Quelques parties de notre code en ont besoin et pour ces quelques parties, nous devons écrire notre code de manière thread-safe à l'aide de verrous, de mutex ou de synchronisation.


nonatomic

  • Puisqu'il n'y a rien de tel que la corbeille de Mac OS, personne ne se soucie de savoir si vous obtenez toujours une valeur (<- Cela pourrait potentiellement entraîner un plantage), ni personne ne se soucie si quelqu'un essaie de lire à mi-chemin de votre écriture (bien que L'écriture à mi-chemin dans la mémoire est très différente de l'écriture à mi-chemin sur papier, sur la mémoire, cela pourrait vous donner une valeur stupide folle d'avant, tandis que sur le papier, vous ne voyez que la moitié de ce qui a été écrit) -> Ne garantit pas de ne pas planter, car il n'utilise pas le mécanisme de libération automatique.
  • Ne garantit pas la lecture de toutes les valeurs écrites!
  • Est plus rapide qu'atomique

Globalement, ils sont différents sous 2 aspects:

  • Plantage ou non en raison de la présence ou non d'un pool de libération automatique.

  • Permettre d'être lu en plein milieu d'une «écriture pas encore terminée ou d'une valeur vide» ou ne pas autoriser et autoriser la lecture uniquement lorsque la valeur est entièrement écrite.


9

Si vous utilisez votre propriété dans du code multithread, vous pourrez voir la différence entre les attributs non atomiques et atomiques. Nonatomic est plus rapide qu'atomic et atomic est thread-safe, pas nonatomic.

Vijayendra Tripathi a déjà donné un exemple pour un environnement multi-thread.


9
  • -Atomic signifie qu'un seul thread accède à la variable (type statique).
  • -Atomic est sûr pour les threads.
  • -mais ses performances sont lentes

Comment déclarer:

Comme atomic est par défaut,

@property (retain) NSString *name;

ET dans le fichier d'implémentation

self.name = @"sourov";

Supposons qu'une tâche liée à trois propriétés soit

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

Toutes les propriétés fonctionnent en parallèle (comme de manière asynchrone).

Si vous appelez "nom" à partir du thread A ,

Et

En même temps, si vous appelez

[self setName:@"Datta"]

du fil B ,

Si maintenant la propriété de nom * est nonatomic alors

  • Il renverra la valeur "Datta" pour A
  • Il renverra la valeur "Datta" pour B

C'est pourquoi non atomique est appelé thread dangereux, mais ses performances sont rapides en raison de l'exécution parallèle

Maintenant, si la propriété * name est atomique

  • Il assurera la valeur "Sourov" pour A
  • Ensuite, il renverra la valeur "Datta" pour B

Voilà pourquoi atomic est appelé thread Safe et c'est pourquoi il est appelé lecture-écriture safe

Une telle opération de situation fonctionnera en série. Et lent dans les performances

- Nonatomique signifie que plusieurs threads accèdent à la variable (type dynamique).

- Nonatomic est dangereux pour les threads.

- mais ses performances sont rapides

-Nonatomic n'est PAS un comportement par défaut, nous devons ajouter un mot-clé nonatomic dans l'attribut de propriété.

Pour In Swift Confirmer que les propriétés Swift ne sont pas anatomiques au sens ObjC. L'une des raisons est que vous vous demandez si l'atomicité par propriété est suffisante pour vos besoins.

Référence: https://forums.developer.apple.com/thread/25642

Pour plus d'informations, veuillez visiter le site Web http://rdcworld-iphone.blogspot.in/2012/12/variable-property-attributes-or.html


4
Comme beaucoup d'autres l'ont dit, ce atomicn'est PAS du thread-safe! Il est plus résistant aux problèmes de threads, mais pas thread-safe. Il garantit simplement que vous obtiendrez une valeur entière, alias une valeur "correcte" (niveau binaire), mais en aucun cas, il garantira qu'il s'agit de la valeur actuelle et "correcte" pour votre logique métier (il pourrait s'agir d'une valeur passée et invalide par votre logique).
Alejandro Iván

6

Atomicité atomique (par défaut)

Atomic est la valeur par défaut: si vous ne tapez rien, votre propriété est atomic. Une propriété atomique est garantie que si vous essayez de la lire, vous récupérerez une valeur valide. Il ne donne aucune garantie quant à cette valeur, mais vous récupérerez de bonnes données, pas seulement de la mémoire indésirable. Ce que cela vous permet de faire, c'est que si vous avez plusieurs threads ou plusieurs processus pointant vers une seule variable, un thread peut lire et un autre thread peut écrire. S'ils frappent en même temps, le thread du lecteur est garanti d'obtenir l'une des deux valeurs: soit avant la modification, soit après la modification. Ce que l'atomique ne vous donne pas, c'est une sorte de garantie quant à laquelle de ces valeurs vous pourriez obtenir. Atomic est vraiment communément confondu avec le thread-safe, et ce n'est pas correct. Vous devez garantir la sécurité de votre fil d'autres façons.

non anatomique

D'un autre côté, non atomique, comme vous pouvez probablement le deviner, signifie simplement «ne faites pas ce genre de choses atomiques». Ce que vous perdez, c'est cette garantie que vous récupérez toujours quelque chose. Si vous essayez de lire au milieu d'une écriture, vous pourriez récupérer des données inutiles. Mais d'un autre côté, vous allez un peu plus vite. Parce que les propriétés atomiques doivent faire de la magie pour garantir que vous récupérerez une valeur, elles sont un peu plus lentes. S'il s'agit d'une propriété à laquelle vous accédez beaucoup, vous souhaiterez peut-être passer à non anatomique pour vous assurer que vous n'encourez pas cette pénalité de vitesse. Accès

courtoisie https://academy.realm.io/posts/tmi-objective-c-property-attributes/

Les attributs de propriété d'atomicité (atomique et non atomique) ne sont pas reflétés dans la déclaration de propriété Swift correspondante, mais les garanties d'atomicité de l'implémentation d'Objective-C restent valables lorsque la propriété importée est accessible à partir de Swift.

Donc - si vous définissez une propriété atomique dans Objective-C, elle restera atomique lorsqu'elle sera utilisée par Swift.

courtoisie https://medium.com/@YogevSitton/atomic-vs-non-atomic-properties-crash-course-d11c23f4366c


5

La propriété atomique garantit de conserver une valeur entièrement initialisée quel que soit le nombre de threads exécutant getter et setter dessus.

La propriété nonatomique spécifie que les accesseurs synthétisés définissent ou retournent simplement une valeur directement, sans aucune garantie de ce qui se passe si cette même valeur est accédée simultanément à partir de différents threads.


3

Atomic signifie qu'un seul thread peut accéder à la variable à la fois (type statique). Atomic est thread-safe, mais il est lent.

Non anatomique signifie que plusieurs threads peuvent accéder à la variable en même temps (type dynamique). Nonatomic n'est pas sûr pour les threads, mais il est rapide.


1

Si vous utilisez atomic, cela signifie que le thread sera sûr et en lecture seule. Si vous utilisez non anatomique, cela signifie que les threads multiples accèdent à la variable et que le thread n'est pas sûr, mais il est exécuté rapidement, fait des opérations de lecture et d'écriture; c'est un type dynamique.


1

La vérité est qu'ils utilisent le verrouillage par rotation pour implémenter la propriété atomique. Le code comme ci-dessous:

 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

Pour simplifier toute la confusion, comprenons le verrouillage mutex.

Le verrouillage Mutex, selon le nom, verrouille la mutabilité de l'objet. Donc, si l'objet est accessible par une classe, aucune autre classe ne peut accéder au même objet.

Dans iOS, @sychronisefournit également le verrou mutex. Maintenant, il sert en mode FIFO et garantit que le flux n'est pas affecté par deux classes partageant la même instance. Cependant, si la tâche se trouve sur le thread principal, évitez d'accéder à l'objet à l'aide des propriétés atomiques car il peut contenir votre interface utilisateur et dégrader les performances.


-1

Atomic: assurez la sécurité du fil en verrouillant le fil à l'aide de NSLOCK.

Non atomique: n'assure pas la sécurité du fil car il n'y a pas de mécanisme de verrouillage du fil.


-1

Propriétés atomiques : - Lorsqu'une variable affectée avec une propriété atomique qui signifie qu'elle n'a qu'un accès au thread et qu'elle sera sûre pour les threads et sera bonne en termes de performances, aura un comportement par défaut.

Propriétés non atomiques : - Lorsqu'une variable affectée avec une propriété atomique signifie qu'elle a un accès multi-thread et qu'elle ne sera pas thread-safe et sera lente dans la perspective des performances, aura un comportement par défaut et lorsque deux threads différents veulent accéder à la variable en même temps cela donnera des résultats inattendus.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.