Tengo un doble error gratuito al usar std :: shared_ptr y trato de saber por qué. Estoy usando shared_ptr en un entorno multiproceso, un hilo a veces reemplaza algún elemento en una matriz global

std::shared_ptr<Bucket>  globalTable[100]; // global elements storage

Usando:

globalTable[idx].reset(newBucket);

Y el otro hilo lee esta tabla a veces usando:

std::shared_ptr<Bucket> bkt(globalTable[pIdx]);
// do calculations with bkt-> items

Después de esto, recibo un error doble libre y AddressSanitizer dice que el segundo código intenta liberar un objeto que fue destruido por el primero. Como es posible ? Como sé, shared_ptr debe ser completamente seguro para subprocesos.

2
Oleg 25 feb. 2018 a las 01:56

2 respuestas

La mejor respuesta

Reset no le garantiza la seguridad de los hilos.

Las asignaciones y el recuento de referencias son seguros para subprocesos, como se explica aquí

Para satisfacer los requisitos de seguridad de subprocesos, los contadores de referencia se incrementan típicamente usando un equivalente de std :: atomic :: fetch_add con std :: memory_order_relaxed (la disminución requiere un orden más fuerte para destruir de forma segura el bloque de control).

Si varios subprocesos acceden al mismo shared_ptr, puede tener una condición de carrera.

Si varios subprocesos de ejecución acceden al mismo shared_ptr sin sincronización y cualquiera de esos accesos utiliza una función de miembro no constante de shared_ptr, se producirá una carrera de datos; las sobrecargas shared_ptr de funciones atómicas se pueden utilizar para evitar la carrera de datos.

El restablecimiento de su función no es constante, por lo que pertenece a esa categoría. Necesita usar mutex u otro mecanismo de sincronización.

http://en.cppreference.com/w/cpp/memory/shared_ptr

2
Gabriel 24 feb. 2018 a las 23:11

No todas las operaciones en un std::shared_ptr son seguras para subprocesos.

Específicamente, los recuentos de referencias se administran de manera atómica, pero es su responsabilidad asegurarse de que la instancia std::shared_ptr a la que accede no se modifique simultáneamente.

Fallas en esa responsabilidad, lo que resulta en una carrera de datos y el comportamiento indefinido esperado, manifestándose como un doble libre en tu caso.

2
Deduplicator 24 feb. 2018 a las 23:03