2009-08-01 3 views
6

Posso eseguire una delle seguenti operazioni? Bloccheranno/sbloccheranno correttamente lo stesso oggetto? Perché o perché no? Supponiamo che ci siano molti thread identici usando la variabile globale "obj", che è stata inizializzata prima che iniziassero tutti i thread.Modifica dell'oggetto di blocco nella sezione @synchronized

1.

@synchronized(obj) { 
    [obj release]; 
    obj = nil; 
} 

2.

@synchronized(obj) { 
    obj = [[NSObject new] autorelease]; 
} 
+0

Nota: correlata a http://stackoverflow.com/questions/1215330/ –

+1

Dopo aver letto questo post in SO, ho deciso di indagare su @synchronized un po 'più a fondo e scrivere un post sul blog. Potresti trovarlo utile: http://rykap.com/objective-c/2015/05/09/synchronized.html – rjkaplan

+0

@rjkaplan il tuo link è rotto –

risposta

8

Risposta breve: no, non si blocca correttamente/sblocco, e tali approcci dovrebbero essere evitati.

La mia prima domanda è perché si vorrebbe fare qualcosa di simile, poiché questi approcci annullano in primo luogo gli scopi e i vantaggi dell'utilizzo di un blocco @synchronized.

Nel secondo esempio, una volta che un thread modifica il valore di obj, ogni thread successivo che raggiunge il blocco @synchronized si sincronizzerà sul nuovo oggetto, non sull'oggetto originale. Per i thread N, creerai in modo esplicito N oggetti autoreleased e il runtime potrebbe creare fino a N blocchi ricorsivi associati a tali oggetti. Scambiare l'oggetto su cui ci si sincronizza all'interno della sezione critica è un no-no fondamentale della concorrenza thread-safe. Non farlo Mai. Se più thread possono accedere in modo sicuro a un blocco contemporaneamente, omettere semplicemente @synchronized.

Nel tuo primo esempio, i risultati potrebbero essere indefiniti, e certamente non quello che vuoi, sia. Se il runtime utilizza solo il puntatore dell'oggetto per trovare il blocco associato, il codice potrebbe funzionare correttamente, ma la sincronizzazione su nil non ha alcun effetto percettibile nei miei test semplici, quindi di nuovo si sta utilizzando @synchronized in modo inutile, poiché non offre protezione di sorta.

sinceramente non sto cercando di essere duro, dato che immagino che probabilmente sei solo curioso del costrutto. Sto solo formulando questo messaggio per (si spera) impedendo a te e agli altri di scrivere codice che è fatalmente imperfetto, specialmente se si suppone che si sincronizzi correttamente. In bocca al lupo!

+0

Nel mio caso particolare (il motivo per cui ho trovato questo Q/A) è che voglio fare qualcosa di simile (scusa, nessuna buona formattazione nei commenti) ... '@synchornized (obj) {if (obj! = Nil) {... [fare roba, snipare]; obj = nil}} '(* NOTA: * Sono sotto ARC, quindi ottengo il mio' release' gratuitamente. Quello che voglio è, se c'è un obj, per sincronizzarlo mentre faccio casino. Se è nulla, io non mi interessa davvero. – Olie