2012-02-10 18 views
16

Apple's multithreading docs ¡no liste NSIndexPath como seguro o no! Como una clase inmutable, generalmente espero que sea segura.¿NSIndexPath es seguro para hilos?

Anteriormente, estoy seguro de que la documentación utilizada para indicar que las instancias NSIndexPath se compartían y eran únicas a nivel mundial. 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 bastantes 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: ¿las instancias actuales son seguras, pero que la lógica para sacarlas de la memoria caché compartida no es así? ¿Alguien tiene alguna idea?

He aquí un ejemplo seguimiento de la pila Por cierto:

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í, esto es un ejemplo NSIndexPath tratando de compararse a una instancia desasignado.

+1

¿Qué hace con esas rutas de índice, y dónde ocurre el bloqueo? Los errores de subprocesamiento múltiple son misteriosos, un bloqueo con un 'NSIndexPath' no necesariamente significa que el problema está en' NSIndexPath'. – hamstergene

+0

Ejecuto una solicitud de búsqueda y luego ordeno los resultados según su método '-indexPath'. Internamente, cada vez que se invoca, ese método crea una ruta de índice que representa la posición del objeto en el árbol. Sospecho que me están entregando compartidos 'NSIndexPath's que luego serán desasignados poco después en otro hilo. –

+0

¿dónde se origina NSIndexPath? ¿Es una propiedad del objeto recuperado? –

Respuesta

4

Hasta el momento la mejor respuesta que tengo es como sospecho:

A partir de OS X 10.7 y el 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 instancias existentes no lo es.

Para mi método que devuelve caminos de índice bajo demanda, lo hice:

- (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 bloqueo de caminos de índice.

Las rutas de índice se crean por -indexPathByAddingIndex: o +indexPathWithIndex:.

Los resultados que estoy viendo me hacen bastante seguro de que (antes de 10.7/iOS5) estos métodos devuelven una instancia existente de NSIndexPath.Sin embargo, esa instancia no queda retenida por el hilo actual, por lo que el hilo que creó la instancia (principal en nuestro caso) está liberando la ruta (probablemente al abrir el grupo de autorrelease) y dejando nuestro hilo de trabajo con un puntero colgante. que se bloquea cuando se usa, como se ve en la pregunta.

Es todo un poco aterrador, porque si mi análisis es correcto, el baile retain/autorelease que he agregado es simplemente reemplazar una condición de carrera con otra, menos probable.

Antes de 10.7/iOS5, puedo pensar en una sola solución verdadera: limitar toda la creación de rutas de índice al hilo principal. Eso podría ser bastante lento si se llama mucho a ese código, por lo que podría mejorarse, a costa de la memoria, manteniendo algún tipo de caché de instancia para que los hilos de fondo puedan usarse. Si la memoria caché conserva una ruta, sabrá que no será desasignada por la cadena principal.

1

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

Pero "hilo seguro" no significa que no puede causar bloqueos al ser liberado por un hilo antes de usarlo en otro. En general, el hilo seguro significa que sus métodos de mutador contienen bloqueo para evitar fallos debido a dos hilos que configuran propiedades al mismo tiempo (por eso las clases sin métodos de mutador generalmente son seguras para hilos, aunque los getters perezosos y las instancias compartidas también pueden causar problemas).

Parece que su error es más probable debido al uso de un grupo de autorrelease o algún otro mecanismo que hace que su objeto sea lanzado en un momento fuera de su control. Probablemente debería asegurarse de que los objetos accedidos simultáneamente se almacenen en propiedades de clases de larga duración para que pueda controlar su vida útil.

Crear un objeto liberado automáticamente y acceder a él desde otro hilo después de haber eliminado todas las referencias fuertes es un peligroso juego de carreras que probablemente cause bloqueos difíciles de rastrear independientemente de si el objeto en cuestión es "hilo" seguro".

+0

Sí, entiendo la variedad de peligros en el código de subprocesos múltiples. No estoy creando estos objetos en un hilo y espero que sigan viviendo en otro hilo. Estoy creando los objetos preguntando 'NSIndexPath' por ellos en el hilo de trabajo. Según tengo entendido, en 10.6 y anteriores, las instancias de 'NSIndexPath' se comparten globalmente. Sospecho que este caché global no es seguro para subprocesos, en lugar de las instancias individuales. –

+1

Todavía puede leer los documentos de iOS 4.3/OS 10.6 en el Organizador en Xcode si descarga los conjuntos de documentos anteriores y busca todos los conjuntos de documentos. He encontrado la línea a la que se refiere: "Los objetos NSIndexPath son únicos y compartidos. Si ya existe una ruta de índice que contiene el índice o los índices especificados, ese objeto se devuelve en lugar de una nueva instancia". Y sí, parece que se ha eliminado en los últimos documentos, por lo que quizás tenga razón acerca de que NSIndexPath no es seguro para subprocesos en 10.6. –

+0

Aha, ¡me olvidé de que todavía puedes acceder a los viejos documentos! –

Cuestiones relacionadas