2012-07-14 30 views
19

¿El subproceso unique_ptr es seguro? ¿Es imposible para el siguiente código imprimir el mismo número dos veces?¿Es seguro el hilo unique_ptr?

#include <memory> 
#include <string> 
#include <thread> 
#include <cstdio> 

using namespace std; 

int main() 
{ 
    unique_ptr<int> work; 

    thread t1([&] { 
     while (true) { 
      const unique_ptr<int> localWork = move(work); 
      if (localWork) 
       printf("thread1: %d\n", *localWork); 
      this_thread::yield(); 
     } 
    }); 

    thread t2([&] { 
     while (true) { 
      const unique_ptr<int> localWork = move(work); 
      if (localWork) 
       printf("thread2: %d\n", *localWork); 
      this_thread::yield(); 
     } 
    }); 

    for (int i = 0; ; i++) { 
     work.reset(new int(i)); 

     while (work) 
      this_thread::yield(); 
    } 

    return 0; 
} 

Respuesta

16

No, no es seguro para subprocesos .

Ambos subprocesos pueden potencialmente move puntero de trabajo sin sincronización explícita, por lo que es posible que ambos subprocesos obtengan el mismo valor, o ambos obtengan algún puntero no válido ... es un comportamiento indefinido.

Si quieres hacer algo como esto correctamente, es probable que tenga que usar algo como std::atomic_exchange por lo que ambos hilos pueden leer/modificar el puntero de trabajo compartido con la semántica correctas.

+0

"Emocionantemente, cuando y si esto sucede, también dará como resultado la doble liberación del número entero". Que podría*. Puede que no. Puede resultar en no liberar el entero en absoluto. Puede resultar en que ambas versiones movidas tengan la mitad del valor del puntero. Podría hacer todo tipo de cosas. –

+0

Cierto, estaba haciendo algunas suposiciones sobre la arquitectura que no están realmente justificadas. – Useless

7

Según Msdn:

El siguiente hilo de seguridad reglas se aplican a todas las clases en la Norma C++ Library (excepto las clases shared_ptr y iostream, como se describe abajo).

Un único objeto es seguro para la lectura de subprocesos múltiples. Para el ejemplo , dado un objeto A, es seguro leer A desde el hilo 1 y desde el hilo 2 simultáneamente.

Si un único objeto se escribe con un subproceso, entonces todo lee y escribe en ese objeto en el mismo u otros subprocesos debe estar protegido. Por ejemplo, dado un objeto A, si el hilo 1 está escribiendo en A, entonces se debe evitar que el hilo 2 lea o escriba en A.

Es seguro leer y escribir en una instancia de un tipo incluso si otro hilo está leyendo o escribiendo en una instancia diferente del mismo tipo. por ejemplo, objetos dados A y B del mismo tipo, es seguro si A se está escribiendo en el hilo 1 y B se está leyendo en hilo 2.

28

unique_ptr es seguro para subprocesos cuando se usa correctamente. Rompiste la regla no escrita: nunca pasarás unique_ptr entre hilos por referencia.

La filosofía detrás de unique_ptr es que tiene un propietario único (único) en todo momento. Por eso, siempre puede pasarlo de manera segura entre hilos sin sincronización, pero debe pasarlo por valor, no por referencia. Una vez que crea alias en un unique_ptr, pierde la propiedad de unicidad y todas las apuestas están desactivadas. Lamentablemente, C++ no puede garantizar la singularidad, por lo que se queda con una convención que debe seguir religiosamente. ¡No cree alias en un unique_ptr!

+0

Interesante observación. Intento pensar cuándo tiene sentido transferir unique_ptr por referencia a continuación. Me refiero a cuando hay un caso en el que no quieres pasar la propiedad. – Ghita

+0

Si 'pasar entre hilos' significa comenzar un nuevo hilo con el argumento unique_ptr, entonces podrías reemplazar unique_ptr con casi cualquier tipo y aún así llamarlo seguro para hilos. Cualquier cosa es segura cuando se usa correctamente :) –

+1

u seguro de esto?mi programador paranoico interno me dice que si pasas el subproceso entre subprocesos es UB porque no aseguras seq_cst, también conocido como si lo que apunta es modificado por el subproceso 1 y luego se pasa al subproceso 2, entonces el subproceso 2 podría ver valores obsoletos de señaló cosas. – NoSenseEtAl

Cuestiones relacionadas