Qual è la differenza tra gli attributi atomici e non anatomici?


Risposte:


1761

Gli ultimi due sono identici; "atomico" è il comportamento predefinito (si noti che in realtà non è una parola chiave, è specificato solo dall'assenza dinonatomic - è atomicstato aggiunto come parola chiave nelle ultime versioni di llvm / clang).

Supponendo che tu stia @ sintetizzando le implementazioni del metodo, atomico contro non atomico modifica il codice generato. Se stai scrivendo il tuo setter / getter, atomico / non anatomico / trattenere / assegnare / copiare sono puramente consultivi. (Nota: @synthesize è ora il comportamento predefinito nelle ultime versioni di LLVM. Non è inoltre necessario dichiarare le variabili di istanza; anch'esse verranno sintetizzate automaticamente e avranno un_ anteprime al loro nome per impedire l'accesso diretto accidentale).

Con "atomico", il setter / getter sintetizzato assicurerà che a valore intero sia sempre restituito dal getter o impostato dal setter, indipendentemente dall'attività del setter su qualsiasi altro thread. Cioè, se il thread A si trova nel mezzo del getter mentre il thread B chiama il setter, un valore effettivo effettivo - un oggetto con rilascio automatico, molto probabilmente - verrà restituito al chiamante in A.

In nonatomic, tali garanzie non sono fatte. Così,nonatomic è notevolmente più veloce di "atomico".

Ciò che "atomico" non lo fa fa è fornire garanzie sulla sicurezza del filo. Se il thread A chiama il getter contemporaneamente con il thread B e C chiamando il setter con valori diversi, il thread A può ottenere uno dei tre valori restituiti: quello precedente alla chiamata di qualsiasi setter o uno dei valori passati nei setter in B e C. Allo stesso modo, l'oggetto può finire con il valore di B o C, non c'è modo di dirlo.

Garantire l'integrità dei dati - una delle principali sfide della programmazione multi-thread - si ottiene con altri mezzi.

Aggiungendo a questo:

atomicity di una singola proprietà non può inoltre garantire la sicurezza del thread quando sono in gioco più proprietà dipendenti.

Prendere in considerazione:

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

In questo caso, il thread A potrebbe rinominare l'oggetto chiamando setFirstName:e quindi chiamando setLastName:. Nel frattempo, il thread B può chiamare fullNametra le due chiamate del thread A e riceverà il nuovo nome associato al vecchio cognome.

Per risolvere questo problema, è necessario un modello transazionale . Vale a dire qualche altro tipo di sincronizzazione e / o esclusione che consente di escludere l'accesso fullNamedurante l'aggiornamento delle proprietà dipendenti.


21
Dato che qualsiasi codice thread-safe eseguirà il proprio blocco, ecc., Quando vorresti utilizzare gli accessi alle proprietà atomiche? Ho problemi a pensare a un buon esempio.
Daniel Dickison,

8
@bbum Ha senso. Mi piace il tuo commento a un'altra risposta che la sicurezza del thread è più una preoccupazione a livello di modello. Da una definizione di sicurezza del thread IBM: ibm.co/yTEbjY "Se una classe è implementata correttamente, il che è un altro modo per dire che è conforme alle sue specifiche, nessuna sequenza di operazioni (legge o scrive campi pubblici e chiama a metodi pubblici) su oggetti di quella classe dovrebbe essere in grado di mettere l'oggetto in uno stato non valido, osservare l'oggetto in uno stato non valido o violare qualsiasi invariante, precondizione o postcondizione della classe. "
Ben Flynn,

6
Ecco un esempio simile a quello di @StevenKramer: ho un @property NSArray* astronomicalEvents;elenco che elenca i dati che voglio visualizzare nell'interfaccia utente. Quando l'applicazione avvia il puntatore punta a un array vuoto, l'app estrae i dati dal Web. Quando la richiesta Web viene completata (in un thread diverso) l'app crea un nuovo array, quindi imposta atomicamente la proprietà su un nuovo valore di puntatore. È thread-safe e non ho dovuto scrivere alcun codice di blocco, a meno che non mi manchi qualcosa. Mi sembra abbastanza utile.
bugloaf,

10
@HotLicks Un altro divertente; su alcune architetture (non ricordo quale), i valori a 64 bit passati come argomento potrebbero essere passati metà in un registro e metà nello stack. atomicimpedisce letture a metà valore tra thread. (È stato un bug divertente da rintracciare.)
bbum

8
@congliu La discussione A restituisce un oggetto senza retain/autoreleasedanza. Il thread B rilascia oggetto. Il thread A diventa boom . atomicassicura che il thread A abbia un riferimento forte (un conteggio di mantenimento +1) per il valore restituito.
bbum

360

Questo è spiegato nella documentazione di Apple , ma di seguito sono riportati alcuni esempi di ciò che sta realmente accadendo.

Si noti che non esiste una parola chiave "atomica", se non si specifica "non anatomico", la proprietà è atomica, ma se si specifica esplicitamente "atomico" si verificherà un errore.

Se non si specifica "nonatomic", la proprietà è atomica, ma è comunque possibile specificare esplicitamente "atomic" nelle versioni recenti.

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

- (UITextField *) userName {
    return userName;
}

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

Ora, la variante atomica è un po 'più complicata:

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

Fondamentalmente, la versione atomica deve prendere un lucchetto per garantire la sicurezza del thread, e sta anche aumentando il conteggio dei ref sull'oggetto (e il conteggio del rilascio automatico per bilanciarlo) in modo che l'oggetto sia garantito per il chiamante, altrimenti lì è una potenziale condizione di competizione se un altro thread sta impostando il valore, facendo scendere il conteggio di riferimento a 0.

Esistono in realtà un gran numero di varianti diverse di come funzionano queste cose a seconda che le proprietà siano valori o oggetti scalari e come interagiscono keep, copy, readonly, nonatomic, ecc. In generale i sintetizzatori di proprietà sanno solo come fare la "cosa giusta" per tutte le combinazioni.


8
@Louis Gerbarg: credo che la tua versione del setter (nonatomic, keep) non funzionerà correttamente se provi ad assegnare lo stesso oggetto (ovvero userName == userName_)
Florin

5
Il tuo codice è leggermente fuorviante; non vi è alcuna garanzia su quali getter / setter atomici siano sincronizzati. Criticamente, @property (assign) id delegate;non è sincronizzato su nulla (iOS SDK GCC 4.2 ARM -Os), il che significa che c'è una corsa tra [self.delegate delegateMethod:self];e foo.delegate = nil; self.foo = nil; [super dealloc];. Vedi stackoverflow.com/questions/917884/…
tc.

@fyolnish Non sono sicuro di cosa _val/ valsono, ma no, non proprio. Il getter per un atomico copy/ retainproprietà deve assicurarsi che non restituisca un oggetto il cui conto diventa zero a causa del setter chiamato in un altro thread, il che significa essenzialmente che deve leggere l'ivar, mantenerlo assicurandosi che il setter non abbia sovrascritto e rilasciato, quindi rilasciarlo automaticamente per bilanciare la conservazione. Ciò significa essenzialmente che sia il getter che il setter devono usare un lock (se il layout della memoria è stato riparato dovrebbe essere fattibile con le istruzioni CAS2; purtroppo -retainè una chiamata di metodo).
tc.

@tc È passato un bel po 'di tempo ma probabilmente intendevo scrivere questo: gist.github.com/fjolnir/5d96b3272c6255f6baae Ma sì, è possibile che il vecchio valore venga letto da un lettore prima di setFoo: restituisce e rilasciato prima del il lettore lo restituisce. Ma forse se il setter usasse -autorelease invece di -release, ciò risolverebbe questo problema.
Fjölnir,

@fyolnish Purtroppo no: questo si rilascia automaticamente sul thread del setter, mentre deve essere rilasciato automaticamente sul thread del getter. Sembra anche che ci sia una (sottile) possibilità di rimanere senza stack perché stai usando la ricorsione.
tc.

170

Atomico

  • è il comportamento predefinito
  • assicurerà che il presente processo sia completato dalla CPU, prima che un altro processo acceda alla variabile
  • non è veloce, in quanto garantisce che il processo sia completato completamente

Non-Atomic

  • NON è il comportamento predefinito
  • più veloce (per codice sintetizzato, ovvero per variabili create utilizzando @property e @synthesize)
  • non thread-safe
  • può comportare un comportamento imprevisto, quando due processi diversi accedono alla stessa variabile contemporaneamente

137

Il modo migliore per capire la differenza è usare il seguente esempio.

Supponiamo che esista una proprietà di stringa atomica chiamata "nome" e se si chiama [self setName:@"A"]dal thread A, si chiama [self setName:@"B"]dal thread B e si chiama [self name]dal thread C, allora tutte le operazioni su thread diversi verranno eseguite in serie, il che significa che se un thread sta eseguendo un setter o getter, quindi altri thread aspetteranno.

Questo rende la proprietà "nome" di lettura / scrittura sicura, ma se un altro thread, D, chiama [name release]contemporaneamente, questa operazione potrebbe produrre un arresto anomalo perché qui non sono coinvolte chiamate setter / getter. Ciò significa che un oggetto è in lettura / scrittura sicuro (ATOMIC), ma non thread-safe in quanto un altro thread può inviare contemporaneamente qualsiasi tipo di messaggio all'oggetto. Lo sviluppatore dovrebbe garantire la sicurezza dei thread per tali oggetti.

Se la proprietà "name" non era anatomica, tutti i thread nell'esempio precedente - A, B, C e D eseguiranno simultaneamente producendo risultati imprevedibili. In caso di atomico, uno di A, B o C verrà eseguito per primo, ma D può comunque essere eseguito in parallelo.


116

La sintassi e la semantica sono già ben definite da altre eccellenti risposte a questa domanda. Poiché l' esecuzione e le prestazioni non sono ben dettagliate, aggiungerò la mia risposta.

Qual è la differenza funzionale tra questi 3?

Ho sempre considerato l'atomico come un default piuttosto curioso. A livello di astrazione su cui lavoriamo, l'utilizzo di proprietà atomiche per una classe come veicolo per ottenere il 100% di sicurezza del filo è un caso angolare. Per programmi multithread veramente corretti, l'intervento del programmatore è quasi certamente un requisito. Nel frattempo, le caratteristiche prestazionali e l'esecuzione non sono state ancora dettagliate in dettaglio. Dopo aver scritto alcuni programmi fortemente multithread nel corso degli anni, avevo dichiarato le mie proprietà per nonatomictutto il tempo perché l'atomica non era ragionevole per nessuno scopo. Durante la discussione dei dettagli delle proprietà atomiche e non anatomiche di questa domanda , ho fatto un po 'di profiling incontrando alcuni risultati curiosi.

Esecuzione

Ok. La prima cosa che vorrei chiarire è che l'implementazione di blocco è definita e astratta. Louis usa @synchronized(self)nel suo esempio: l'ho visto come una fonte comune di confusione. L'implementazione non utilizza effettivamente@synchronized(self) ; utilizza i blocchi di spin a livello di oggetto . L'illustrazione di Louis è buona per un'illustrazione di alto livello che usa costrutti che conosciamo tutti, ma è importante sapere che non li usa @synchronized(self).

Un'altra differenza è che le proprietà atomiche manterranno / rilasceranno i tuoi oggetti all'interno del getter.

Prestazione

Ecco la parte interessante: le prestazioni che utilizzano gli accessi alle proprietà atomiche in casi non contestati (ad esempio a thread singolo) possono essere molto veloci in alcuni casi. In casi non ideali, l'uso di accessi atomici può costare oltre 20 volte il sovraccarico di nonatomic. Mentre il caso contestato con 7 thread era 44 volte più lento per la struttura a tre byte (2,2 GHz Core i7 Quad Core, x86_64). La struttura a tre byte è un esempio di una proprietà molto lenta.

Nota a margine interessante: gli accessori definiti dall'utente della struttura a tre byte erano 52 volte più veloci degli accessori atomici sintetizzati; o l'84% della velocità degli accessori non anatomici sintetizzati.

Anche gli oggetti nei casi contestati possono superare 50 volte.

A causa del numero di ottimizzazioni e variazioni nelle implementazioni, è abbastanza difficile misurare gli impatti del mondo reale in questi contesti. Potresti spesso sentire qualcosa del tipo "Fidati, a meno che non ti profilassi e trovi che è un problema". A causa del livello di astrazione, in realtà è abbastanza difficile misurare l'impatto reale. Raccogliere i costi effettivi dai profili può richiedere molto tempo e, a causa delle astrazioni, abbastanza impreciso. Inoltre, ARC vs MRC può fare la differenza.

Quindi facciamo un passo indietro, non concentrandoci sull'implementazione degli accessi alle proprietà, includeremo i soliti sospetti come objc_msgSended esamineremo alcuni risultati di alto livello del mondo reale per molte chiamate a un NSStringgetter in casi non contestati (valori in secondi):

  • MRC | non anatomico | Getter implementati manualmente: 2
  • MRC | non anatomico | getter sintetizzato: 7
  • MRC | atomico | getter sintetizzato: 47
  • ARC | non anatomico | getter sintetizzato: 38 (nota: l'ARC sta aggiungendo il conteggio dei riferimenti in bicicletta qui)
  • ARC | atomico | getter sintetizzato: 47

Come probabilmente avete indovinato, l'attività di conteggio dei riferimenti / ciclismo è un contributo significativo con l'atomica e sotto ARC. Vedresti anche maggiori differenze nei casi contestati.

Anche se prendo molta attenzione alle prestazioni, dico ancora Semantics First! . Nel frattempo, le prestazioni sono una priorità bassa per molti progetti. Tuttavia, conoscere i dettagli di esecuzione e i costi delle tecnologie che usi sicuramente non fa male. Dovresti usare la tecnologia giusta per le tue esigenze, scopi e capacità. Spero che questo ti risparmierà qualche ora di confronto e ti aiuti a prendere una decisione più informata durante la progettazione dei tuoi programmi.


MRC | atomico | getter sintetizzato: 47 ARC | atomico | getter sintetizzato: 47 Cosa li rende uguali? ARC non dovrebbe avere più spese generali?
SDEZero,

2
Quindi, se le proprietà atomiche sono cattive, sono quelle predefinite. Per aumentare il codice del boilerplate?
Kunal Balani,

@ LearnCocos2D ho appena testato il 10.8.5 sulla stessa macchina, mirando al 10.8, per il caso non contestato a thread singolo con un caso NSStringnon immortale: -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%- i risultati oggi sono leggermente diversi. Non stavo facendo alcun @synchronizedconfronto. @synchronizedè semanticamente diverso, e non lo considero un buon strumento se si hanno programmi concorrenti non banali. se hai bisogno di velocità, evita @synchronized.
justin

hai questo test online da qualche parte? Continuo ad aggiungere il mio qui: github.com/LearnCocos2D/LearnCocos2D/tree/master/…
LearnCocos2D

@ LearnCocos2D non li ho preparati per il consumo umano, mi dispiace.
justin

95

Atomico = sicurezza della filettatura

Non atomico = Nessuna sicurezza della filettatura

Sicurezza del filo:

Le variabili di istanza sono thread-safe se si comportano correttamente quando vi si accede da più thread, indipendentemente dalla pianificazione o dall'interleaving dell'esecuzione di tali thread da parte dell'ambiente di runtime e senza alcuna sincronizzazione aggiuntiva o altro coordinamento da parte del codice chiamante.

Nel nostro contesto:

Se un thread modifica il valore dell'istanza, il valore modificato è disponibile per tutti i thread e solo un thread alla volta può modificare il valore.

Dove usare atomic:

se si accederà alla variabile di istanza in un ambiente multithread.

Implicazione di atomic:

Non veloce come nonatomicperché nonatomicnon richiede alcun lavoro di watchdog su questo dal runtime.

Dove usare nonatomic:

Se la variabile di istanza non verrà modificata da più thread, puoi usarla. Migliora le prestazioni.


3
Tutto ciò che dici qui è corretto, ma l'ultima frase è essenzialmente "sbagliata", Dura, per la programmazione di oggi. È davvero inconcepibile che ti preoccupi di provare a "migliorare le prestazioni" in questo modo. (Voglio dire, prima che te ne accorgessi nei prossimi anni, "non utilizzeresti ARC", "non userai NSString perché è lento!" E così via.) Per fare un esempio estremo, sarebbe come dire "squadra, non inserire commenti nel codice perché ci rallenta ". Non esiste una pipeline di sviluppo realistica in cui si desideri ottenere miglioramenti teorici (inesistenti) per motivi di inaffidabilità.
Fattie,

3
@JoeBlow è un dato di fatto che puoi verificarlo qui developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
Durai Amuthan.H

1
Durai, FWIW, che collega direttamente contraddice la tua tesi di "Atomic = sicurezza del filo". Nel documento Apple afferma esplicitamente: "L'atomicità delle proprietà non è sinonimo di sicurezza del thread di un oggetto". In pratica, l'atomico è raramente sufficiente per ottenere la sicurezza della filettatura.
Rob

69

Ho trovato una spiegazione abbastanza ben messa delle proprietà atomiche e non atomiche qui . Ecco un testo pertinente dallo stesso:

"atomico" significa che non può essere scomposto. In termini di sistema operativo / programmazione, una chiamata di funzione atomica non può essere interrotta: l'intera funzione deve essere eseguita e non sostituita dalla CPU dal normale cambio di contesto del sistema operativo fino al completamento. Nel caso in cui non lo sapessi: poiché la CPU può fare solo una cosa alla volta, il sistema operativo ruota l'accesso alla CPU a tutti i processi in esecuzione in piccoli intervalli di tempo, per dare il illusionemultitasking. Lo scheduler della CPU può (e fa) interrompere un processo in qualsiasi momento della sua esecuzione, anche durante la chiamata a metà funzione. Pertanto, per azioni come l'aggiornamento di variabili contatore condivise in cui due processi potrebbero tentare di aggiornare la variabile contemporaneamente, devono essere eseguiti "atomicamente", ovvero

Quindi indovinerei che in questo caso atomico significa che i metodi di lettura degli attributi non possono essere interrotti - in effetti significa che le variabili che vengono lette dal metodo non possono cambiare il loro valore a metà perché alcuni altri thread / call / funzioni ottengono scambiato sulla CPU.

Poiché le atomicvariabili non possono essere interrotte, il valore da esse contenuto in qualsiasi punto (thread-lock) è garantito come non corrotto , sebbene, garantendo che questo blocco thread ne renda più lento l'accesso. non-atomicle variabili, d'altra parte, non offrono tale garanzia ma offrono il lusso di un accesso più rapido. Per riassumere, vai avanti non-atomicquando sai che le tue variabili non saranno accessibili da più thread contemporaneamente e velocizzerai le cose.


1
Il collegamento è interrotto. ; (
Rob

Questo è il problema con i link :( per fortuna, ho citato il testo pertinente nella mia risposta
tipycalFlow

67

Dopo aver letto tanti articoli, articoli Stack Overflow e creato applicazioni demo per controllare gli attributi delle proprietà variabili, ho deciso di mettere insieme tutte le informazioni sugli attributi:

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

Nell'articolo Attributi o modificatori delle proprietà delle variabili in iOS puoi trovare tutti gli attributi sopra menzionati e questo ti aiuterà sicuramente.

  1. atomic

    • atomic significa che solo un thread accede alla variabile (tipo statico).
    • atomic è thread-safe.
    • Ma è lento nelle prestazioni
    • atomic è il comportamento predefinito
    • Gli accessi atomici in un ambiente non garbage collection (ad esempio quando si utilizza la conservazione / rilascio / rilascio automatico) utilizzeranno un blocco per garantire che un altro thread non interferisca con l'impostazione / acquisizione corretta del valore.
    • In realtà non è una parola chiave.

    Esempio:

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

    • nonatomic significa che più thread accedono alla variabile (tipo dinamico).
    • nonatomic non è sicuro.
    • Ma è veloce nelle prestazioni
    • nonatomicNON è un comportamento predefinito. Dobbiamo aggiungere la nonatomicparola chiave nell'attributo proprietà.
    • Può comportare un comportamento imprevisto, quando due diversi processi (thread) accedono alla stessa variabile contemporaneamente.

    Esempio:

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

In che modo assegnare e confermare / mantenere entrambi sono predefiniti?
BangOperator,

strong viene fornito con ARC, il mantenimento era predefinito prima di ARC
abdullahselek,

56

Atomico:

Atomic garantisce che l'accesso alla proprietà verrà eseguito in modo atomico. Ad esempio, restituisce sempre un oggetto completamente inizializzato, qualsiasi get / set di una proprietà su un thread deve essere completato prima che un altro possa accedervi.

Se immagini che la seguente funzione si verifichi su due thread contemporaneamente, puoi vedere perché i risultati non sarebbero belli.

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

  ...
}

Pro: il ritorno di oggetti completamente inizializzati ogni volta rende la scelta migliore in caso di multi-threading.

Contro: Performance hit, rende l'esecuzione un po 'più lenta

Non atomico:

A differenza di Atomic, non garantisce sempre il ritorno completo degli oggetti inizializzati.

Pro: esecuzione estremamente veloce.

Contro: possibilità di immondizia in caso di multi-threading.


5
Questo commento non ha molto senso. Puoi chiarire? Se guardi esempi sul sito Apple, la parola chiave atomica si sincronizza sull'oggetto mentre ne aggiorna le proprietà.
Andrew Grant,

52

Prima la risposta più semplice: non c'è differenza tra i tuoi secondi due esempi. Per impostazione predefinita, gli accessori di proprietà sono atomici.

Gli accessi atomici in un ambiente non garbage collection (ad esempio quando si utilizza la conservazione / rilascio / rilascio automatico) utilizzeranno un blocco per garantire che un altro thread non interferisca con l'impostazione / acquisizione corretta del valore.

Consulta la sezione " Prestazioni e threading " della documentazione di Apple Objective-C 2.0 per ulteriori informazioni e per altre considerazioni sulla creazione di app multi-thread.


8
Due ragioni. Prima di tutto, per il codice sintetizzato genera più velocemente (ma non un codice thread-safe). In secondo luogo, se stai scrivendo accessori per i clienti che non sono atomici, ti consente di annotare per ogni futuro utente che il codice non è atomico quando sta leggendo la sua interfaccia, senza renderli implementativi.
Louis Gerbarg,


31

Atomico significa che solo un thread accede alla variabile (tipo statico). Atomic è thread-safe, ma è lento.

Non anatomico significa che più thread accedono alla variabile (tipo dinamico). Nonatomic non è sicuro, ma è veloce.


14

Atomic è sicuro per i thread , è lento e garantisce (non garantito) che viene fornito solo il valore bloccato, indipendentemente dal numero di thread che stanno tentando di accedere nella stessa zona. Quando si usa atomico, un pezzo di codice scritto all'interno di questa funzione diventa la parte della sezione critica, alla quale può eseguire solo un thread alla volta.

Assicura solo la sicurezza del filo; non lo garantisce. Quello che voglio dire è che assumi un autista esperto per la tua auto, tuttavia non garantisce che l'auto non incontrerà un incidente. Tuttavia, la probabilità rimane il minimo.

Atomico: non può essere scomposto, quindi il risultato è previsto. Con nonatomico: quando un altro thread accede alla zona di memoria, può modificarlo, quindi il risultato è inaspettato.

Code Talk:

Atomic rende sicuri getter e setter del thread delle proprietà. per esempio se hai scritto:

self.myProperty = value;

è thread-safe.

[myArray addObject:@"Abc"] 

NON è thread-safe.


Non so come sia arrivato l'ultimo paragrafo, ma è semplicemente sbagliato, non esiste una cosa come "copia privata".
picco il

13

Non esiste una parola chiave "atomica"

@property(atomic, retain) UITextField *userName;

Possiamo usare come sopra

@property(retain) UITextField *userName;

Vedi la domanda Stack Overflow Ricevo problemi se uso @property (atomico, conserva) NSString * myString .


10
"Esiste tale parola chiave", che la parola chiave non è richiesta per impostazione predefinita e anche il valore predefinito non significa che la parola chiave non esiste.
Matthijn,

4
Questo non è corretto La parola chiave esiste. Questa risposta è fuorviante e vorrei incoraggiarla a smontarla.
sethfri,

12

atomico (impostazione predefinita)

Atomic è l'impostazione predefinita: se non si digita nulla, la proprietà è atomica. Una proprietà atomica è garantita che se provi a leggere da essa, otterrai un valore valido. Non fornisce alcuna garanzia su quale possa essere quel valore, ma otterrai buoni dati, non solo memoria indesiderata. Ciò che ti consente di fare è se hai più thread o più processi che puntano a una singola variabile, un thread può leggere e un altro thread può scrivere. Se colpiscono contemporaneamente, il thread del lettore ottiene uno dei due valori: prima della modifica o dopo la modifica. Ciò che atomico non ti dà è una sorta di garanzia su quale di quei valori potresti ottenere. Atomic è davvero comunemente confuso con l'essere thread-safe, e questo non è corretto. È necessario garantire la sicurezza del thread in altri modi.

nonatomic

Il rovescio della medaglia, non atomico, come probabilmente puoi immaginare, significa semplicemente "non fare quella roba atomica". Quello che perdi è quella garanzia di ottenere sempre qualcosa in cambio. Se si tenta di leggere nel mezzo di una scrittura, è possibile recuperare i dati di immondizia. D'altra parte, vai un po 'più veloce. Poiché le proprietà atomiche devono fare un po 'di magia per garantire che tu possa recuperare un valore, sono un po' più lente. Se è una proprietà a cui stai accedendo molto, potresti voler passare a non anatomico per assicurarti di non incorrere in quella penalità di velocità.

Vedi di più qui: https://realm.io/news/tmi-objective-c-property-attributes/


11

L' impostazione predefinita è atomic, ciò significa che ti costa prestazioni ogni volta che usi la proprietà, ma è thread-safe. Ciò che fa Objective-C è impostare un blocco, quindi solo il thread effettivo può accedere alla variabile, purché il setter / getter sia eseguito.

Esempio con MRC di una proprietà con ivar _internal:

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

Quindi questi ultimi due sono gli stessi:

@property(atomic, retain) UITextField *userName;

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

D'altra parte non nonatomicaggiunge nulla al tuo codice. Quindi è thread-safe solo se codifichi tu stesso il meccanismo di sicurezza.

@property(nonatomic, retain) UITextField *userName;

Le parole chiave non devono essere scritte come primo attributo della proprietà.

Non dimenticare, questo non significa che la proprietà nel suo insieme sia thread-safe. È solo la chiamata del metodo del setter / getter. Ma se usi un setter e successivamente un getter allo stesso tempo con 2 thread diversi, potrebbe anche essere rotto!


10

Prima di iniziare: devi sapere che ogni oggetto in memoria deve essere deallocato dalla memoria affinché un nuovo scrittore possa accadere. Non puoi semplicemente scrivere sopra qualcosa come fai su carta. È necessario prima cancellarlo (dealloc) e quindi è possibile scrivere su di esso. Se al momento la cancellazione (o la metà) non è stata ancora scritta (o la metà è stata scritta) e si tenta di leggere, potrebbe essere molto problematico! Atomico e non anatomico ti aiutano a trattare questo problema in diversi modi.

Prima leggi questa domanda e poi leggi la risposta di Bbum . Inoltre, leggi il mio riepilogo.


atomic garantirà SEMPRE

  • Se due persone diverse vogliono leggere e scrivere allo stesso tempo, il tuo giornale non si limiterà a bruciare! -> La tua applicazione non si bloccherà mai, anche in condizioni di gara.
  • Se una persona sta cercando di scrivere e ha scritto solo 4 delle 8 lettere da scrivere, quindi non è possibile leggere nel mezzo, la lettura può essere eseguita solo quando tutte le 8 lettere sono scritte -> Nessuna lettura (get) avverrà su 'un thread che sta ancora scrivendo', cioè se ci sono 8 byte in byte da scrivere e solo 4 byte sono scritti - fino a quel momento, non ti è permesso leggere da esso. Ma dal momento che ho detto che non si arresterà in modo anomalo, leggerebbe dal valore di un oggetto rilasciato automaticamente .
  • Se prima di scrivere si ha cancellato quello che in precedenza è stato scritto su carta e poi qualcuno vuole leggere si può ancora leggere. Come? Leggerai da qualcosa di simile al Cestino di Mac OS (poiché il Cestino non è ancora cancellato al 100% ... è in un limbo) ---> Se ThreadA dovesse leggere mentre ThreadB è già stato allocato per scrivere, otterrai un valore dal valore finale completamente scritto da ThreadB o ottenere qualcosa dal pool di rilascio automatico.

Conservare i conteggi è il modo in cui la memoria è gestita in Objective-C. Quando si crea un oggetto, ha un conteggio di mantenimento di 1. Quando si invia a un oggetto un messaggio di mantenimento, il suo conteggio di mantenimento viene incrementato di 1. Quando si invia a un oggetto un messaggio di rilascio, il suo conteggio di mantenimento viene diminuito di 1. Quando si crea invia a un oggetto un messaggio di rilascio automatico , il suo conteggio dei ritardi viene diminuito di 1 in un momento successivo. Se il conteggio di conservazione di un oggetto viene ridotto a 0, viene deallocato.

  • Atomic non garantisce la sicurezza della filettatura, sebbene sia utile per ottenere la sicurezza della filettatura. La sicurezza della discussione è relativa a come scrivi il tuo codice / da quale coda di thread stai leggendo / scrivendo. Garantisce solo il multithreading non crashable.

Che cosa?! Il multithreading e la sicurezza dei thread sono diversi?

Sì. Multithreading significa: più thread possono leggere contemporaneamente un dato condiviso e non andremo in crash, ma non garantisce che non stai leggendo da un valore non rilasciato automaticamente. Con la sicurezza del thread, è garantito che ciò che leggi non viene rilasciato automaticamente. Il motivo per cui non rendiamo tutto atomico per impostazione predefinita è che ci sono costi di prestazione e per la maggior parte delle cose non c'è davvero bisogno della sicurezza dei thread. Alcune parti del nostro codice ne hanno bisogno e per quelle poche parti, dobbiamo scrivere il nostro codice in modo thread-safe usando lock, mutex o sincronizzazione.


nonatomic

  • Dal momento che non esiste nulla come Mac OS Cestino, a nessuno importa se ottieni sempre un valore (<- Ciò potrebbe potenzialmente causare un arresto anomalo), né a nessuno importa se qualcuno prova a leggere a metà della tua scrittura (anche se la scrittura a metà strada in memoria è molto diversa dalla scrittura a metà strada sulla carta, in memoria potrebbe darti un valore stupido e folle rispetto a prima, mentre sulla carta vedi solo metà di ciò che è stato scritto) -> Non garantisce di non andare in crash, perché non utilizza il meccanismo di rilascio automatico.
  • Non garantisce la lettura di valori scritti completi!
  • È più veloce dell'atomico

Complessivamente sono diversi in 2 aspetti:

  • Arresto anomalo o meno a causa del fatto di avere o meno un pool di rilascio automatico.

  • Consentire di essere letto nel bel mezzo di una 'scrittura non ancora completata o di un valore vuoto' o non consentire e consentire solo di leggere quando il valore è completamente scritto.


9

Se stai usando la tua proprietà in codice multi-thread, allora potresti vedere la differenza tra attributi non anatomici e atomici. Nonatomic è più veloce di atomico e atomico è thread-safe, non nonatomico.

Vijayendra Tripathi ha già fornito un esempio per un ambiente multi-thread.


9
  • -Atomico significa che solo un thread accede alla variabile (tipo statico).
  • -Atomic è thread-safe.
  • -ma è lento nelle prestazioni

Come dichiarare:

Poiché atomic è predefinito,

@property (retain) NSString *name;

E nel file di implementazione

self.name = @"sourov";

Supponiamo che un'attività sia correlata a tre proprietà

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

Tutte le proprietà funzionano in parallelo (come in modo asincrono).

Se chiami "name" dal thread A ,

E

Allo stesso tempo, se chiami

[self setName:@"Datta"]

dalla filettatura B ,

Ora se la proprietà * name non è anatomica, allora

  • Restituirà il valore "Datta" per A
  • Restituirà il valore "Datta" per B

Ecco perché non atomico è chiamato thread non sicuro, ma è veloce nelle prestazioni a causa dell'esecuzione parallela

Ora se la proprietà * name è atomica

  • Garantirà il valore "Sourov" per A
  • Quindi restituirà il valore "Datta" per B

Ecco perché atomic si chiama thread Safe ed è per questo che si chiama read-write safe

Tale operazione di situazione si svolgerà in serie. E lento nelle prestazioni

- Nonatomico significa che più thread accedono alla variabile (tipo dinamico).

- Nonatomic è il thread non sicuro.

- ma è veloce nelle prestazioni

-Nonatomic NON è un comportamento predefinito, è necessario aggiungere una parola chiave nonatomic nell'attributo proprietà.

Per In Swift Confermare che le proprietà Swift sono non anatomiche nel senso ObjC. Uno dei motivi è quello di pensare se l'atomicità per proprietà è sufficiente per le tue esigenze.

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

Per ulteriori informazioni, visitare il sito Web http://rdcworld-iphone.blogspot.in/2012/12/variable-property-attributes-or.html


4
Come molti molti altri hanno già detto, NONatomic è sicuro per i thread! È più resistente ai problemi dei thread, ma non è sicuro per i thread. Garantisce solo che otterrai un valore intero, ovvero un valore "corretto" (livello binario), ma non garantisce in alcun modo che sia il valore corrente e "corretto" per la tua logica aziendale (potrebbe essere un valore passato e non valido dalla tua logica).
Alejandro Iván,

6

Atomicità atomica (impostazione predefinita)

Atomic è l'impostazione predefinita: se non si digita nulla, la proprietà è atomica. Una proprietà atomica è garantita che se provi a leggere da essa, otterrai un valore valido. Non fornisce alcuna garanzia su quale possa essere quel valore, ma otterrai buoni dati, non solo memoria indesiderata. Ciò che ti consente di fare è se hai più thread o più processi che puntano a una singola variabile, un thread può leggere e un altro thread può scrivere. Se colpiscono contemporaneamente, il thread del lettore ottiene uno dei due valori: prima della modifica o dopo la modifica. Ciò che atomico non ti dà è una sorta di garanzia su quale di quei valori potresti ottenere. Atomic è davvero comunemente confuso con l'essere thread-safe, e questo non è corretto. È necessario garantire la sicurezza del thread in altri modi.

nonatomic

Il rovescio della medaglia, non atomico, come probabilmente puoi immaginare, significa semplicemente "non fare quella roba atomica". Quello che perdi è quella garanzia di ottenere sempre qualcosa in cambio. Se si tenta di leggere nel mezzo di una scrittura, è possibile recuperare i dati di immondizia. D'altra parte, vai un po 'più veloce. Poiché le proprietà atomiche devono fare un po 'di magia per garantire che tu possa recuperare un valore, sono un po' più lente. Se è una proprietà a cui stai accedendo molto, potresti voler passare a non anatomico per assicurarti di non incorrere in quella penalità di velocità. Accesso

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

Gli attributi della proprietà di atomicità (atomica e non anatomica) non si riflettono nella corrispondente dichiarazione di proprietà Swift, ma le garanzie di atomicità dell'implementazione Objective-C rimangono valide quando si accede alla proprietà importata da Swift.

Quindi - se si definisce una proprietà atomica in Objective-C rimarrà atomica quando viene utilizzata da Swift.

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


5

La proprietà atomica assicura di mantenere un valore completamente inizializzato indipendentemente da quanti thread stanno eseguendo il getter e il setter su di esso.

La proprietà nonatomica specifica che gli accessori sintetizzati semplicemente impostano o restituiscono un valore direttamente, senza garanzie su cosa succede se si accede allo stesso valore simultaneamente da thread diversi.


3

Atomico significa che solo un thread alla volta può accedere alla variabile (tipo statico). Atomic è thread-safe, ma è lento.

Non anatomico significa che più thread possono accedere alla variabile contemporaneamente (tipo dinamico). Nonatomic non è sicuro, ma è veloce.


1

Se stai usando atomico, significa che il thread sarà sicuro e di sola lettura. Se si utilizza nonatomico, significa che i thread multipli accedono alla variabile ed è thread non sicuro, ma viene eseguito rapidamente, ha eseguito operazioni di lettura e scrittura; questo è un tipo dinamico.


1

La verità è che usano spin lock per implementare la proprietà atomica. Il codice come di seguito:

 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

Per semplificare l'intera confusione, comprendiamo il blocco mutex.

Il blocco mutex, come da nome, blocca la mutabilità dell'oggetto. Pertanto, se l'oggetto è accessibile da una classe, nessun'altra classe può accedere allo stesso oggetto.

In iOS, @sychronisefornisce anche il blocco mutex. Ora funziona in modalità FIFO e garantisce che il flusso non sia influenzato da due classi che condividono la stessa istanza. Tuttavia, se l'attività si trova sul thread principale, evitare di accedere all'oggetto utilizzando le proprietà atomiche in quanto potrebbe contenere l'interfaccia utente e peggiorare le prestazioni.


-1

Atomico: garantire la sicurezza del filo bloccando il filo con NSLOCK.

Non atomico: non garantisce la sicurezza del thread in quanto non esiste un meccanismo di blocco del thread.


-1

Proprietà atomiche : - Quando una variabile assegnata con la proprietà atomica significa che ha un solo accesso al thread e sarà thread-safe e sarà buona in termini di prestazioni, avrà un comportamento predefinito.

Proprietà non atomiche : - Quando una variabile assegnata con proprietà atomica significa che ha accesso multi-thread e non sarà thread-safe e sarà lenta nella prospettiva delle prestazioni, avrà un comportamento predefinito e quando due thread diversi vogliono accedere alla variabile contemporaneamente darà risultati inaspettati.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.