Qual è la differenza tra gli attributi atomici e non atomici? (atomic nonatomic)

Condividi questo articolo:


@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;

Qual è la differenza operativa tra questi tre?

Gli ultimi due sono identici; “atomico” è il comportamento predefinito (si noti che in realtà non è una parola chiave, è specificato solo dall’assenza di non anatomico – atomico è stato 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 _ anteposto al loro nome per impedire l’accesso diretto accidentale).

Con “atomico”, il setter / getter sintetizzato assicurerà che un 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 rilasciato automaticamente, molto probabilmente – verrà restituito al chiamante in A.

In ambito non anatomico, non viene fornita tale garanzia. Pertanto, il nonatomico è considerevolmente più veloce di “atomico”.

Ciò che “atomico” non fa è fornire garanzie sulla sicurezza del filo. Se il thread A chiama il getter contemporaneamente al 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

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

Tener conto di:

@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 fullName tra le due chiamate del thread A e riceverà il nuovo nome associato al vecchio cognome.

Per risolvere questo problema, è necessario un modello transazionale. Cioè qualche altro tipo di sincronizzazione e / o esclusione che consente di escludere l’accesso a fullName durante l’aggiornamento delle proprietà dipendenti.

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 interagiscano conservazione, copia, sola lettura, non anatomica, ecc. In generale i sintetizzatori di proprietà sanno solo come fare la “cosa giusta” per tutte le combinazioni

Per risolvere questo problema, è necessario un modello transazionale. Cioè qualche altro tipo di sincronizzazione e / o esclusione che consente di escludere l’accesso a fullName durante l’aggiornamento delle proprietà dipendenti.

Hai bisogno di informazioni, una consulenza o un preventivo ?
Compila il form e illustrami il tuo progetto


Condividi questo articolo: