2009-07-31 13 views
183

@synchronized non usa "lock" e "unlock" per ottenere l'esclusione reciproca? Come si blocca/sblocca allora?In che modo @synchronized blocca/sblocca in Objective-C?

L'output del seguente programma è solo "Hello World".

+0

Nota: relativo a http://stackoverflow.com/questions/1215765/ –

+10

Non è necessario sovrascrivere init se non è necessario. Il runtime chiama automaticamente l'implementazione della superclasse se non si sovrascrive un metodo. –

+1

Una cosa importante da notare è che il codice sopra non è sincronizzato. L'oggetto 'lock' viene creato su ogni chiamata, quindi non ci sarà mai un caso in cui un blocco' @ sincronizzato' ne blocca un altro. E questo significa che non c'è esclusione reciproca.) Ovviamente, l'esempio precedente sta facendo l'operazione in 'main', quindi non c'è nulla da escludere comunque, ma non si dovrebbe copiare ciecamente quel codice altrove. –

risposta

296

La sincronizzazione a livello di linguaggio Objective-C utilizza il mutex, proprio come fa NSLock. Semanticamente ci sono alcune piccole differenze tecniche, ma è fondamentalmente corretto considerarle come due interfacce separate implementate su un'entità comune (più primitiva).

In particolare con un NSLock si ha un blocco esplicito mentre con @synchronized si ha un blocco implicito associato all'oggetto che si sta utilizzando per la sincronizzazione. Il vantaggio del blocco del livello di linguaggio è che il compilatore lo capisce in modo che possa affrontare problemi di scoping, ma meccanicamente si comportano sostanzialmente allo stesso modo.

Si può pensare a @synchronized come una riscrittura del compilatore:

- (NSString *)myString { 
    @synchronized(self) { 
    return [[myString retain] autorelease]; 
    } 
} 

si trasforma in:

- (NSString *)myString { 
    NSString *retval = nil; 
    pthread_mutex_t *self_mutex = LOOK_UP_MUTEX(self); 
    pthread_mutex_lock(self_mutex); 
    retval = [[myString retain] autorelease]; 
    pthread_mutex_unlock(self_mutex); 
    return retval; 
} 

Questo non è esattamente corretto, perché l'attuale trasformazione è più complesso e utilizza i blocchi ricorsivi, ma dovrebbe arrivare il punto.

+17

Stai dimenticando anche la gestione delle eccezioni che @synchronized fa per te. E a quanto ho capito, gran parte di questo viene gestito in fase di runtime. Ciò consente l'ottimizzazione su serrature uncontended, ecc. –

+5

Come ho già detto, le cose generate effettivamente sono più complesse, ma non mi sentivo di scrivere direttive di sezione per costruire le tabelle di svolgimento DWARF3 ;-) –

+0

E non posso biasimare tu. :-) Si noti inoltre che OS X utilizza il formato Mach-O invece di DWARF. –

-2

Collega semplicemente un semaforo a ogni oggetto e lo utilizza.

+0

Tecnicamente, crea un blocco mutex, ma l'idea di base è corretta. Vedi la diva di Apple su: http://developer.apple.com/documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html#//apple_ref/doc/uid/10000057i-CH8-SW16 –

+3

Non solo un mutex, ma una serratura ricorsiva. – kperryua

37

In Objective-C, un blocco @synchronized gestisce automaticamente il blocco e lo sblocco (nonché le eventuali eccezioni) automaticamente. Il runtime genera in modo dinamico essenzialmente un NSRecursiveLock associato all'oggetto su cui si sta eseguendo la sincronizzazione. This Apple documentation lo spiega in modo più dettagliato. Questo è il motivo per cui non visualizzi i messaggi di log dalla sottoclasse NSLock: l'oggetto su cui esegui la sincronizzazione può essere qualsiasi cosa, non solo un NSLock.

Fondamentalmente, @synchronized (...) è una comoda soluzione che semplifica il codice. Come la maggior parte delle astrazioni di semplificazione, ha associato un sovraccarico (consideralo un costo nascosto), ed è bene essere consapevoli di ciò, ma la prestazione non è probabilmente l'obiettivo supremo quando si usano tali costrutti.

29

realtà

{ 
    @synchronized(self) { 
    return [[myString retain] autorelease]; 
    } 
} 

trasforma direttamente in:

// needs #import <objc/objc-sync.h> 
{ 
    objc_sync_enter(self) 
    id retVal = [[myString retain] autorelease]; 
    objc_sync_exit(self); 
    return retVal; 
} 

Questa API disponibili dal iOS 2.0 e importati utilizzando ...

#import <objc/objc-sync.h> 
+0

Quindi non fornisce supporto per gestire in modo pulito le eccezioni generate? – Dustin

+0

È documentato da qualche parte? – jbat100

+6

C'è una coppia sbilanciata lì. – Potatoswatter

1

implementazione di Apple @synchronized è open source e può essere trovato here.Mike cenere ha scritto due davvero interessante post su questo argomento:

In poche parole si ha una tabella che le mappe oggetto puntatori (utilizzando i loro indirizzi di memoria come chiavi) per pthread_mutex_t serrature , che sono bloccati e sbloccati, se necessario.

Problemi correlati