2012-08-09 4 views
5

Ho una classe che utilizza un array mutabile che viene modificato una volta dopo molte letture (arrivano nuovi elementi).Evitare di copiare NSMutableArray per la lettura con scritture multithread

Il problema è che quando arriva il momento di mutare la matrice, le letture continuano a venire.

Attualmente per evitare questo problema ogni volta che si legge qualcosa lo fa nel corso di una copia:

[[theArray copy] operation] //operation being indexOfObject:, objectAtIndex: objectsAtIndexes:, etc. 

La copia sta diventando molto costoso, soprattutto quando non v'è alcuna necessità di (tutte quelle volte in cui la matrice è non essendo mutato).

Come posso bloccare l'array per ritardare l'accesso ad esso quando viene mutato?

+0

perché non si rende questo array come proprietà di classe e durante la dichiarazione lo si rende atomico, quindi il compilatore si prenderà cura di qualsiasi tipo di sincronizzazione tra i thread. – kidsid49

risposta

9

Mettere tutti gli array in una coda di invio seriale. Ciò impedirà l'esecuzione simultanea di due operazioni contemporaneamente. Vedere "Eliminating Lock-based Code" nella Guida alla programmazione della concorrenza.

Se è possibile richiedere iOS> = 4.3, è possibile utilizzare una coda personalizzata simultanea e dispatch barriers per le operazioni di mutazione. Ciò consentirà che le letture avvengano simultaneamente, ma quando è necessaria una scrittura verranno trattenute fino al termine della scrittura. Il blocco presentato come barriera si esegue essenzialmente in serie su una coda simultanea - non inizierà fino a quando tutti i blocchi precedenti non saranno terminati, né i blocchi successivi inizieranno fino al completamento del blocco barriera. (Questa è la versione GCD del blocco di lettura-scrittura che Justin menziona). Ti dirigo verso l'inimitabile Mike Ash per samples of this.

+1

Fatto correttamente, questo consente lettori paralleli e non bloccanti. È sicuramente la soluzione preferita oggi. –

2

in questo caso, si prenderà in considerazione l'utilizzo di un blocco di lettura/scrittura. Il cacao non li fornisce, ma pthread_rwlock_t è disponibile nelle interfacce pthreads - dichiarato in pthread.h. nota che questo sarà molto più efficiente (per il tuo utilizzo) di @synchronized, o anche un semplice lucchetto.

5

L'approccio più semplice è quello di utilizzare @synchronized, in questo modo:

-(void) accessTheArray { 
    MyClass *obj; 
    @synchronized(theArray) { 
     obj = [theArray objectAtIndex:...]; 
    } 
    [obj someMessage]; 
} 

EDIT: Se non si utilizza ARC, si potrebbe desiderare di mantenere/autorelease l'oggetto, altrimenti potrebbe essere rimosso dal array (e rilasciato) prima che venga chiamato someMessage (grazie per omz per questo eccellente commento).

+0

Va notato che mentre Xcode non riconosce @synchronized come parola chiave, funziona comunque. –

+0

Se non si utilizza ARC, si potrebbe voler "mantenere"/"autorelease" l'oggetto, altrimenti potrebbe essere rimosso dall'array (e rilasciato) prima che venga chiamato 'someMessage'. – omz

+0

@omz Grazie mille, questo è un commento molto importante! "Piccole cose" come questa mi aiutano ad ottenere un più ampio apprezzamento di quanto sia più facile la mia vita sotto ARC. – dasblinkenlight