objective-c ios multithreading nsmutablearray

objective c - ¿El NSMutableArray de Objective-C es seguro para subprocesos?



ios multithreading (7)

He estado tratando de arreglar este bloqueo por casi una semana. La aplicación se bloquea sin ninguna excepción o stack-trace. La aplicación no se bloquea de ninguna manera mientras se ejecuta a través de instrumentos en modo zombie.

Tengo un método que recibe un llamado en un hilo diferente. La solución que solucionó el problema fue reemplazarla

[self.mutableArray removeAllObjects];

con

dispatch_async(dispatch_get_main_queue(), ^{ [self.searchResult removeAllObjects]; });

Pensé que podría ser un problema de tiempo, así que traté de sincronizarlo, pero aún se bloqueó:

@synchronized(self) { [self.searchResult removeAllObjects]; }

Aquí está el código

- (void)populateItems { // Cancel if already exists [self.searchThread cancel]; self.searchThread = [[NSThread alloc] initWithTarget:self selector:@selector(populateItemsinBackground) object:nil]; [self.searchThread start]; } - (void)populateItemsinBackground { @autoreleasepool { if ([[NSThread currentThread] isCancelled]) [NSThread exit]; [self.mutableArray removeAllObjects]; // Populate data here into mutable array for (loop here) { if ([[NSThread currentThread] isCancelled]) [NSThread exit]; // Add items to mutableArray } } }

¿Este problema con NSMutableArray no es seguro para subprocesos?


El objeto de clases casi NSMutable no es seguro para subprocesos.


No.

No es seguro para subprocesos y si necesita modificar su matriz mutable de otra NSLock debe usar NSLock para asegurarse de que todo transcurra como se planeó:

NSLock *arrayLock = [[NSLock alloc] init]; [...] [arrayLock lock]; // NSMutableArray isn''t thread-safe [myMutableArray addObject:@"something"]; [myMutableArray removeObjectAtIndex:5]; [arrayLock unlock];


Como ya han dicho otros, NSMutableArray no es seguro para subprocesos. En caso de que alguien quiera lograr algo más que eliminar AllObject en un entorno seguro para subprocesos, daré otra solución usando GCD además del que usa el bloqueo. Lo que tienes que hacer es sincronizar las acciones de lectura / actualización (reemplazar / eliminar).

Primero obtén la cola concurrente global:

dispatch_queue_t concurrent_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

Para leer:

- (id)objectAtIndex:(NSUInteger)index { __block id obj; dispatch_sync(self.concurrent_queue, ^{ obj = [self.searchResult objectAtIndex:index]; }); return obj; }

Para insertar:

- (void)insertObject:(id)obj atIndex:(NSUInteger)index { dispatch_barrier_async(self.concurrent_queue, ^{ [self.searchResult insertObject:obj atIndex:index]; }); }

De Apple Doc sobre dispatch_barrier_async:

Cuando el bloque de barrera llega al frente de una cola concurrente privada, no se ejecuta inmediatamente. En cambio, la cola espera hasta que los bloques que se están ejecutando actualmente finalicen la ejecución. En ese punto, el bloque de barrera se ejecuta solo. Los bloques enviados después del bloque de barrera no se ejecutan hasta que se completa el bloque de barrera.

Similar para eliminar:

- (void)removeObjectAtIndex:(NSUInteger)index { dispatch_barrier_async(self.concurrent_queue, ^{ [self.searchResult removeObjectAtIndex:index]; }); }

EDITAR : En realidad encontré otra manera más simple hoy para sincronizar el acceso a un recurso mediante el uso de una cola en serie proporcionada por GCD.

De la guía de programación Apple Concurrency Program> Colas de envío :

Las colas en serie son útiles cuando desea que sus tareas se ejecuten en un orden específico. Una cola en serie ejecuta solo una tarea a la vez y siempre extrae las tareas del jefe de la cola. Puede utilizar una cola en serie en lugar de un bloqueo para proteger un recurso compartido o una estructura de datos mutable. A diferencia de un bloqueo, una cola en serie garantiza que las tareas se ejecuten en un orden predecible. Y siempre que envíe sus tareas a una cola en serie de forma asíncrona, la cola nunca podrá interbloquearse.

Crea tu cola en serie:

dispatch_queue_t myQueue = dispatch_queue_create("com.example.MyQueue", NULL);

Despacho de tareas asincrónicas a la cola en serie:

dispatch_async(myQueue, ^{ obj = [self.searchResult objectAtIndex:index]; }); dispatch_async(myQueue, ^{ [self.searchResult removeObjectAtIndex:index]; });

¡Espero eso ayude!


Dado que se mencionaron colas en serie: con una matriz mutable, no basta con preguntar "¿es seguro para subprocesos?". Por ejemplo, asegurarse de que removeAllObjects no falla es bueno y correcto, pero si otro hilo intenta procesar la matriz al mismo tiempo, procesará la matriz antes o después de eliminar todos los elementos, y usted realmente tiene que piensa cual debería ser el comportamiento

Crear una clase + objeto que sea responsable de esta matriz, crear una cola en serie para ella y realizar todas las operaciones a través de la clase en esa cola en serie es la forma más sencilla de hacer las cosas bien sin hacer que su cerebro sufra problemas de sincronización.



Además de que NSLock también puede usar @synchronized ( condition-object ), solo tienes que asegurarte de que cada acceso de la matriz esté envuelto en un @synchronized con el mismo objeto que actúa como condition-object , si solo deseas modificar los contenidos. de la misma instancia de matriz, entonces puede usar la matriz en sí misma como el objeto de condición ; de lo contrario, tendrá que usar otra cosa que sepa que no desaparecerá, el objeto principal, es decir, uno mismo, es una buena opción porque siempre será el mismo para la misma matriz.

@property atributos atómicos en @property solo harán que establecer el hilo de la matriz sea seguro y no modifique los contenidos, es decir, self.mutableArray = ... es seguro para hilos pero [self.mutableArray removeObject:] no lo es.


Todas las clases de NSMutablexxx no son seguras para subprocesos. Las operaciones que incluyen get, insert, remove, add y replace se deben usar con NSLock. Esta es una lista de clases seguras para subprocesos y thread-unsaufe impartidas por Apple: Resumen de seguridad de subprocesos