2012-07-14 22 views
19

È sicuro un thread unique_ptr? È impossibile che il codice sottostante stampi lo stesso numero due volte?È sicuro il thread 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; 
} 

risposta

16

No, non è thread-safe .

Entrambi i thread possono potenzialmente move il puntatore di lavoro senza sincronizzazione esplicita, quindi è possibile che entrambi i thread ottengano lo stesso valore, o entrambi per ottenere un puntatore non valido ... è un comportamento non definito.

Se si vuole fare qualcosa di simile correttamente, probabilmente è necessario usare qualcosa come std::atomic_exchange in modo da entrambi i fili in grado di leggere/modificare il puntatore del lavoro condiviso con la semantica di destra.

+0

"Eccitante, quando e se ciò accade, si otterrà anche il doppio rilascio dell'intero." Potrebbe*. Potrebbe non farlo. Potrebbe risultare non liberare affatto l'intero. Potrebbe portare a entrambe le versioni spostate con metà del valore del puntatore. Potrebbe fare ogni genere di cose. –

+0

Vero, stavo facendo alcune supposizioni sull'architettura che non sono veramente giustificate. – Useless

7

Secondo Msdn:

Il seguente sicurezza filo regole si applicano a tutte le classi Standard C++ Library (tranne le classi shared_ptr e iostream, come descritto di seguito ).

Un singolo oggetto è thread-safe per la lettura da più thread. Per esempio , dato un oggetto A, è sicuro leggere A dal thread 1 e dal thread 2 contemporaneamente.

Se un singolo oggetto viene scritto da un thread, quindi tutti i valori e le scritture su quell'oggetto sullo stesso o su altri thread devono essere protetti da . Ad esempio, dato un oggetto A, se il thread 1 sta scrivendo su A, al thread 2 deve essere impedito di leggere o scrivere in A.

È sicuro leggere e scrivere su un'istanza di un tipo anche se un altro thread sta leggendo o scrivendo su un'altra istanza dello stesso tipo. Per esempio, dati oggetti A e B dello stesso tipo, è sicuro se A è stato scritto in filo 1 e B vengono letti in filo 2.

28

unique_ptr è thread-safe se usato correttamente. Hai infranto la regola non scritta: non passerai mai unique_ptr tra i thread per riferimento.

La filosofia dietro unique_ptr è che ha un unico (unico) proprietario in ogni momento. Per questo motivo, puoi sempre passare in sicurezza tra i thread senza sincronizzazione, ma devi passarlo per valore, non per riferimento. Una volta creati alias su un unique_ptr, si perde la proprietà di unicità e tutte le scommesse sono disattivate. Sfortunatamente il C++ non può garantire l'unicità, quindi ti rimane una convenzione che devi seguire religiosamente. Non creare alias su un unique_ptr!

+0

Osservazione interessante. Cerco di pensare quando ha senso trasferire unique_ptr per riferimento allora. Voglio dire quando c'è il caso che non vuoi passare la proprietà. – Ghita

+0

Se "passare tra i thread" significa avviare un nuovo thread con argomento unique_ptr, allora potresti sostituire unique_ptr con qualsiasi tipo e lo chiamerai ancora thread-safe. Qualunque cosa sia sicura da thread se usata correttamente :) –

+1

ne sei sicuro?il mio programmatore paranoico interno mi dice che se passi il passaggio tra i thread è UB perché non assicuri seq_cst, alias se ciò che viene up to è modificato da thread 1 e poi up passa a thread 2 quindi thread 2 potrebbe vedere valori stanti di indicò cose. – NoSenseEtAl