std:: seguridad compartida del hilo ptr


He leído que

" Múltiples hilos pueden leer y escribir simultáneamente diferentes objetos shared_ptr, incluso cuando los objetos son copias que comparten propiedad."(MSDN: Seguridad de subprocesos en la Biblioteca Estándar de C++ )

¿Significa eso que cambiar el objeto shared_ptr es seguro ?
Por ejemplo, es el siguiente código considerado seguro:

shared_ptr<myClass> global = make_shared<myClass>();
...

//In thread 1
shared_ptr<myClass> private = global;
...

//In thread 2
global = make_shared<myClass>();
...

Puedo estar seguro en ese caso que el hilo 1 private tendrá el valor original de global o el nuevo valor ¿qué hilo 2 asignado pero de cualquier manera tendrá un shared_ptr válido a MyClass?

==EDITAR==
Sólo para explicar mi motivación. Quiero tener un puntero compartido para mantener mi configuración y tengo un grupo de subprocesos para manejar las solicitudes.
así que global es la configuración global.
thread 1 está tomando la configuración actual a medida que comienza a manejar una solicitud.
thread 2 está actualizando la configuración. (solo se aplica a solicitudes futuras)

Si es trabajo, puedo actualizar el configuración de esa manera sin romperlo en medio de un manejo de solicitud.

Author: Roee Gavirel, 2013-01-23

4 answers

Lo que estás leyendo no significa lo que crees que significa. En primer lugar, pruebe la página msdn para shared_ptr.

Desplácese hacia abajo en la sección "Observaciones" y llegará a la esencia del problema. Básicamente, un shared_ptr<> apunta a un "bloque de control" que es la forma en que realiza un seguimiento de cuántos objetos shared_ptr<> están apuntando realmente al objeto "Real". Así que cuando haces esto:

shared_ptr<int> ptr1 = make_shared<int>();

Mientras que solo hay 1 llamada para asignar memoria aquí a través de make_shared, hay dos bloques "lógicos" que no debes tratar de la misma manera. Uno es el int que almacena el valor real, y el otro es el bloque de control, que almacena toda la shared_ptr<> "magia" que lo hace funcionar.

Es solo el bloque de control en sí el que es seguro para el hilo.

Pongo eso en su propia línea para enfatizar. El contenido del shared_ptr no es seguro para subprocesos, ni tampoco escribir en la misma instancia shared_ptr. Aquí hay algo para demostrar lo que media:

// In main()
shared_ptr<myClass> global_instance = make_shared<myClass>();
// (launch all other threads AFTER global_instance is fully constructed)

//In thread 1
shared_ptr<myClass> local_instance = global_instance;

Esto está bien, de hecho puedes hacer esto en todos los hilos tanto como quieras. Y luego cuando local_instance se destruye (al salir del alcance), también es seguro para el hilo. Alguien puede estar accediendo global_instance y no hará ninguna diferencia. El fragmento que sacó de msdn básicamente significa que "el acceso al bloque de control es seguro para subprocesos", por lo que se pueden crear y destruir otras instancias shared_ptr<> en diferentes subprocesos tanto como sea necesario.

//In thread 1
local_instance = make_shared<myClass>();

Esto está bien. It will afectar al objeto global_instance, pero solo indirectamente. El bloque de control al que apunta se decrementará, pero se hará de una manera segura para los hilos. local_instance ya no apuntará al mismo objeto (o bloque de control) que global_instance.

//In thread 2
global_instance = make_shared<myClass>();

Esto es casi seguro que no está bien si global_instance se accede desde cualquier otro subproceso (que usted dice que está haciendo). Necesita un candado si estás haciendo esto porque estás escribiendo en cualquier lugar donde vive global_instance, no solo leyendo de él. Así que escribir en un objeto desde múltiples los hilos son malos a menos que lo hayas guardado a través de una cerradura. Por lo tanto, puede leer desde global_instance el objeto asignando nuevos objetos shared_ptr<> desde él, pero no puede escribir en él.

// In thread 3
*global_instance = 3;
int a = *global_instance;

// In thread 4
*global_instance = 7;

El valor de a no está definido. Podría ser 7, o podría ser 3, o podría ser cualquier otra cosa también. La seguridad del subproceso de las instancias shared_ptr<> solo se aplica a la administración de instancias shared_ptr<> que se inicializaron entre sí, no a lo que están apuntando.

Para enfatizar lo que quiero decir, mira esto:

shared_ptr<int> global_instance = make_shared<int>(0);

void thread_fcn();

int main(int argc, char** argv)
{
    thread thread1(thread_fcn);
    thread thread2(thread_fcn);
    ...
    thread thread10(thread_fcn);

    chrono::milliseconds duration(10000);
    this_thread::sleep_for(duration);

    return;
}

void thread_fcn()
{
    // This is thread-safe and will work fine, though it's useless.  Many
    // short-lived pointers will be created and destroyed.
    for(int i = 0; i < 10000; i++)
    {
        shared_ptr<int> temp = global_instance;
    }

    // This is not thread-safe.  While all the threads are the same, the
    // "final" value of this is almost certainly NOT going to be
    // number_of_threads*10000 = 100,000.  It'll be something else.
    for(int i = 0; i < 10000; i++)
    {
        *global_instance = *global_instance + 1;
    }
}

A shared_ptr<> es un mecanismo para garantizar que los propietarios de múltiples objetos se aseguren de que un objeto se destruya, no un mecanismo para garantizar que múltiples hilos puedan acceder a un objeto correctamente. Todavía necesita un mecanismo de sincronización separado para usarlo de forma segura en múltiples subprocesos (como std::mutex).

La mejor manera de pensarlo IMO es que shared_ptr<> se asegura de que varias copias que apuntan a la misma memoria no tengan problemas de sincronización para en sí mismo, pero no hace nada por el objeto señalado. Trátalo así.

 71
Author: Kevin Anderson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-24 18:09:13

Para añadir a lo que Kevin escribió, la especificación C++14 tiene soporte adicional para el acceso atómico a los objetos shared_ptr:

20.8.2.6 shared_ptr acceso atómico [útil.smartptr.compartir.atómico]

El acceso simultáneo a un objeto shared_ptr desde múltiples subprocesos no introduce una carrera de datos si el acceso se realiza exclusivamente a través de las funciones de esta sección y la instancia se pasa como primer argumento.

Así que si lo haces:

//In thread 1
shared_ptr<myClass> private = atomic_load(&global);
...

//In thread 2
atomic_store(&global, make_shared<myClass>());
...

Será hilo seguro.

 21
Author: Chris Dodd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-02 04:50:02

Significa que tendrá un shared_ptr válido y un conteo de referencia válido.

Estás describiendo una condición de carrera entre 2 hilos que están tratando de leer/asignar a la misma variable.

Debido a que este es un comportamiento indefinido en general (solo tiene sentido en el contexto y el tiempo del programa individual) shared_ptr no maneja eso.

 4
Author: Yochai Timmer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-25 12:53:32

Las operaciones de lectura no están sujetas a carreras de datos entre sí, por lo tanto, es seguro compartir la misma instancia de shared_ptr entre subprocesos, siempre y cuando todos los subprocesos utilicen métodos const solo (esto incluye la creación de copias de la misma). Tan pronto como un hilo utiliza el método no-const (como en "apunte a otro objeto"), dicho uso ya no es seguro para el hilo.

El ejemplo OP no es seguro para hilos y requeriría el uso de carga atómica en el hilo 1. y atomic store en hilo 2 (sección 2.7.2.5 en C++11) para hacerlo seguro de subprocesos.

La palabra clave en el texto de MSDN es de hecho diferentes objetos shared_ptr, como ya se indicó en respuestas anteriores.

 2
Author: Leon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-03 22:59:06