2012-02-03 16 views
80

estoy leyendo http://gcc.gnu.org/onlinedocs/libstdc++/manual/shared_ptr.html y algunos problemas de seguridad de rosca todavía no están claras para mí:hilo de seguridad std :: shared_ptr explicó

  1. garantías establecidas en que el recuento de referencias se manipula el hilo de seguridad y es independiente de la plataforma, ¿verdad?
  2. Problema similar: el estándar garantiza que solo un hilo (manteniendo la última referencia) llamará a eliminar en el objeto compartido, ¿verdad?
  3. shared_ptr no garantiza ningún hilo de seguridad para el objeto almacenado en él?

EDIT:

Pseudo código:

// Thread I 
shared_ptr<A> a (new A (1)); 

// Thread II 
shared_ptr<A> b (a); 

// Thread III 
shared_ptr<A> c (a); 

// Thread IV 
shared_ptr<A> d (a); 

d.reset (new A (10)); 

restablecimiento de llamada() en el hilo IV eliminará anterior instancia de una clase creada en primer hilo y sustituirla por nueva instancia? Además, después de llamar a reset() en el hilo IV, ¿otros hilos verán solo el objeto recién creado?

+23

Derecha, derecha e derecha. – spraff

+14

debe usar 'make_shared' en lugar de' new' – qdii

Respuesta

67

Como han señalado otros, lo ha descifrado correctamente con respecto a sus 3 preguntas originales.

Pero la parte final de su edición

Calling reset() en el hilo IV eliminará anterior instancia de una clase creada en primer hilo y sustituirla por nueva instancia? Además, después de llamar a reset() en el hilo IV, ¿otros hilos verán solo el objeto recién creado?

es incorrecto. Solo d apuntará al nuevo A(10), y a, b y c continuará apuntar al A(1) original. Esto se puede ver claramente en el siguiente breve ejemplo.

#include <memory> 
#include <iostream> 
using namespace std; 

struct A 
{ 
    int a; 
    A(int a) : a(a) {} 
}; 

int main(int argc, char **argv) 
{ 
    shared_ptr<A> a(new A(1)); 
    shared_ptr<A> b(a), c(a), d(a); 

    cout << "a: " << a->a << "\tb: " << b->a 
    << "\tc: " << c->a << "\td: " << d->a << endl; 

    d.reset(new A(10)); 

    cout << "a: " << a->a << "\tb: " << b->a 
    << "\tc: " << c->a << "\td: " << d->a << endl; 

    return 0;                           
} 

(Claramente, no me molesté con cualquier roscado: que no es un factor en el comportamiento shared_ptr::reset().)

La salida de este código es

a: 1 b: 1 c: 1 d: 1

a: 1 b: 1 c: 1 d: 10

28
  1. correcta, shared_ptr s utilizan atómicas incrementos/decrementos de un valor de recuento de referencia.

  2. El estándar garantiza que solo un hilo llamará al operador delete en un objeto compartido. No estoy seguro si especifica específicamente que el último hilo que borre su copia del puntero compartido será el que llama eliminar (probablemente en la práctica sería el caso).

  3. No, no lo hacen, el objeto almacenado en él puede editarse simultáneamente por varios hilos.

EDIT: Leve seguimiento, si se quiere tener una idea de cómo funcionan los punteros compartida, en general, es posible que desee mirar a la fuente boost::shared_ptr: http://www.boost.org/doc/libs/1_37_0/boost/shared_ptr.hpp.

+3

1. Cuando diga "'shared_ptrs' use incrementos/decrementos atómicos de un valor de recuento de referencia." ¿Quiere decir que no usan ningún bloqueo interno para el incremento/disminución atómico, que hace el cambio de contexto? En un lenguaje simple, ¿múltiples subprocesos pueden incrementar/disminuir el recuento de referencias sin usar el bloqueo? ¿El incremento atómico se realiza mediante instrucciones especiales atomic_test_and_swap/atomic_test_and_increment? –

+0

@rahul el compilador es libre de usar un mutex/lock, pero la mayoría de los buenos compiladores no usarán un mutex/lock en las plataformas donde se puede hacer sin bloqueos. – Bernard

+0

@Bernard: ¿quiere decir que depende de la implementación "compilers std lib shared_ptr" para la plataforma? –

5

std :: shared_ptr no es seguro para subprocesos.

Un puntero compartido es un par de dos punteros, uno para el objeto y otro para un bloque de control (que contiene el contador de referencia, enlaces a punteros débiles ...).

Puede haber varios std :: shared_pointer y cada vez que acceden al bloque de control para cambiar el contador de referencia es threadsafe pero el "std :: shared_ptr" en sí no es threadsafe o atomic.

Si asigna un objeto nuevo a std :: shared_pointer mientras que otro hilo lo usa, podría terminar con el nuevo puntero de objeto pero aún utilizando un puntero al bloque de control del objeto antiguo => CRASH.

Cuestiones relacionadas