multithreading cocoa core-data foundation nsindexpath

multithreading - Es NSIndexPath threadsafe?



cocoa core-data (2)

Los documentos de subprocesos NSIndexPath Apple no listan NSIndexPath como threadsafe o no! Como una clase inmutable, generalmente espero que sea segura para subprocesos.

Anteriormente, estoy seguro de que la documentación utilizada para indicar que NSIndexPath instancias de NSIndexPath eran compartidas y globalmente únicas. Sin embargo, eso parece haber desaparecido ahora, lo que me lleva a sospechar que el diseño fue revisado para iOS5 / Mac OS X 10.7.

Veo muchos informes de fallos de clientes en Mac OS X 10.6 (Snow Leopard) que parecen estar fallando al intentar acceder a una ruta de índice. Por lo tanto, me pregunto: ¿son seguras las hebras de las instancias reales, pero la lógica para sacarlas de la memoria caché compartida no lo es? ¿Alguien tiene alguna idea?

Aquí hay un ejemplo de seguimiento de pila BTW:

Dispatch queue: com.apple.root.default-priority 0 libobjc.A.dylib 0x96513f29 _cache_getImp + 9 1 libobjc.A.dylib 0x965158f0 class_respondsToSelector + 59 2 com.apple.CoreFoundation 0x948bcb49 ___forwarding___ + 761 3 com.apple.CoreFoundation 0x948bc7d2 _CF_forwarding_prep_0 + 50 4 com.apple.Foundation 0x994b10c5 -[NSIndexPath compare:] + 93 5 com.apple.Foundation 0x99415686 _NSCompareObject + 76 6 com.apple.CoreFoundation 0x948af61c __CFSimpleMergeSort + 236 7 com.apple.CoreFoundation 0x948af576 __CFSimpleMergeSort + 70 8 com.apple.CoreFoundation 0x948af38c CFSortIndexes + 252 9 com.apple.CoreFoundation 0x948fe80d CFMergeSortArray + 125 10 com.apple.Foundation 0x994153d3 _sortedObjectsUsingDescriptors + 639 11 com.apple.Foundation 0x994150d8 -[NSArray(NSKeyValueSorting) sortedArrayUsingDescriptors:] + 566

Para mí, esa es una instancia de NSIndexPath intenta compararse con una instancia desasignada.


Apple no menciona específicamente NSIndexPath como seguro para subprocesos, pero sí dicen que las clases inmutables son generalmente seguras y las mutables generalmente no lo son. Dado que NSIndexPath es inmutable, es seguro asumir que es seguro para subprocesos.

Pero "hilo seguro" no significa que no pueda causar bloqueos al ser liberado por un hilo antes de que lo uses en otro. La seguridad de subprocesos generalmente significa que sus métodos de mutación contienen un bloqueo para evitar fallos debidos a la configuración simultánea de propiedades de dos subprocesos (por lo que las clases sin métodos de mutación son generalmente seguras de subprocesos, aunque los usuarios perezosos y los casos compartidos también pueden causar problemas).

Parece que su error es más probable debido al uso de un conjunto de autorelease o algún otro mecanismo que haga que su objeto se libere en un momento fuera de su control. Probablemente debería asegurarse de que cualquier objeto al que se acceda simultáneamente se almacene en propiedades de clases de larga duración para que pueda controlar su vida útil.

Crear un objeto publicado automáticamente y acceder a él desde otro subproceso después de haber eliminado todas las referencias fuertes es un juego de carreras peligroso que puede causar accidentes difíciles de rastrear, independientemente de si el objeto en cuestión es "seguro para subprocesos".


Hasta ahora la mejor respuesta que tengo es como sospecho:

A partir de OS X 10.7 y iOS 5, NSIndexPath es seguro para subprocesos. Antes de eso, las instancias son seguras para subprocesos porque son inmutables, pero la recuperación compartida de las instancias existentes no lo es.

Para mi método que devuelve las rutas de índice bajo demanda, hice esto:

- (NSIndexPath *)indexPath; { NSIndexPath *result = … // create the path as appropriate return [[result retain] autorelease]; }

Desde la implementación de la última línea de código, no hemos tenido más informes de errores de las rutas de índice.

Las rutas del índice se crean mediante -indexPathByAddingIndex: o +indexPathWithIndex:

Los resultados que estoy viendo me dan la certeza de que (antes de 10.7 / iOS5) estos métodos están devolviendo una instancia existente de NSIndexPath . Sin embargo, el hilo actual no retiene esa instancia de ninguna manera, por lo que el hilo que primero creó la instancia (principal en nuestro caso) está liberando el camino (probablemente a través de abrir el grupo de autorelease) y dejando a nuestro hilo trabajador con un puntero colgante. que se bloquea cuando se usa, como se ve en la pregunta.

Todo es un poco aterrador, porque si mi análisis es correcto, el baile de retain / autorelease que he agregado simplemente está reemplazando una condición de carrera por otra, menos probable que sea una.

Antes de 10.7 / iOS5, solo se me ocurre una solución real: limitar toda creación de rutas de índice al subproceso principal. Eso podría ser bastante lento si dicho código se llama mucho, por lo que podría mejorarse, a costa de la memoria, manteniendo algún tipo de caché de instancia para el uso de subprocesos en segundo plano. Si la memoria caché está reteniendo una ruta, entonces usted sabe que no será desasignada por el hilo principal.