2012-08-09 14 views
5

Tengo una clase que usa una matriz mutable que se modifica una vez después de muchas lecturas (llegan nuevos elementos).Evite copiar NSMutableArray para leer con escrituras multiproceso

El problema es que cuando llega el momento de mutar la matriz, las lecturas siguen apareciendo.

la actualidad para evitar este problema cada vez que dice algo lo hace más de una copia:

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

La copia se está volviendo muy caro, sobre todo cuando no hay necesidad de (todos esos momentos en los que la matriz es no está mutado).

¿Cómo puedo bloquear la matriz para retrasar el acceso a ella cuando se está mutando?

+0

¿por qué no hace que esta matriz sea su propiedad de clase y durante la declaración la haga atómica entonces el compilador se encargará de cualquier tipo de sincronización entre hilos? – kidsid49

Respuesta

9

Ponga todos sus accesos a la matriz en una cola de despacho en serie. Eso evitará que ocurran dos operaciones al mismo tiempo. Consulte "Eliminating Lock-based Code" en la Guía de programación de concurrencia.

Si puede requerir iOS> = 4.3, puede usar una cola personalizada simultánea y dispatch barriers para las operaciones de mutación. Esto permitirá que las lecturas sucedan simultáneamente, pero cuando es necesaria una escritura, se retendrán hasta que finalice la escritura. El bloque presentado como barrera se ejecuta esencialmente en serie en una cola concurrente; no comenzará hasta que todos los bloques anteriores hayan finalizado, ni comenzará ningún otro bloque hasta que se complete el bloque de barrera. (Esta es la versión GCD del bloqueo de lectura y escritura que menciona Justin). Le dirijo al inimitable Mike Ash por samples of this.

+1

Hecho correctamente, esto permite lectores paralelos y escritores sin bloqueo. Definitivamente es la solución preferida hoy. –

2

En este caso, consideraría utilizar un bloqueo de lectura/escritura. Cocoa no los proporciona, pero pthread_rwlock_t está disponible en interfaces pthreads - declarado en pthread.h. tenga en cuenta que esto va a ser mucho más eficiente (para su uso) que @synchronized, o incluso un bloqueo simple.

5

El enfoque más simple es utilizar @synchronized, así:

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

EDIT: Si no se usa ARC, es posible que desee retener/AutoRelease el objeto, de lo contrario podría ser removido de la matriz (y liberado) antes de llamar al someMessage (gracias por omz por este excelente comentario).

+0

Cabe señalar que aunque Xcode no reconoce @synchronized como palabra clave, todavía funciona. –

+0

Si no utiliza ARC, es posible que desee 'retener' /' liberar automáticamente' el objeto, de lo contrario, podría eliminarse de la matriz (y soltarse) antes de que se llame a 'someMessage'. – omz

+0

@omz Muchas gracias, este es un comentario muy importante! Las "pequeñas cosas" como esta me ayudan a obtener una apreciación más completa de cuánto más fácil es mi vida bajo ARC. – dasblinkenlight

Cuestiones relacionadas