2014-12-09 13 views
8

Desidero restituire un std::vector. È possibile accedere a questo std::vector da altri thread (lettura e scrittura). Come posso sbloccare il mio std::mutex subito dopo il termine della funzione?Come std :: mutex :: lock finché la funzione non restituisce

Per esempio in qualcosa di simile:

// Value.cpp 
std::vector<int> GetValue() 
{ 
    std::lock_guard<std::mutex> lock(mutex); 

    // Do super smart stuff here 
    // ... 

    return m_value; 
} 

// MyThread.cpp 
auto vec = myVec.GetValue(); 

Ora, che cosa se "fare cose super intelligente qui" è vuota:

// Value.cpp 
std::vector<int> GetValue() 
{ 
    std::lock_guard<std::mutex> lock(mutex); 
    return m_value; 
} 

// MyThread.cpp 
auto vec = myVec.GetValue(); 

Poi è la serratura ancora obbligatorio? Perché?

+1

La costruzione della copia di 'vec' avviene al di fuori del blocco. Se altri thread potrebbero modificare il vettore di riferimento, hai una corsa di dati. – Casey

+0

Questo non funzionerà, si sta restituendo uno stato interno ('m_value') per riferimento. –

+0

@ DieterLücking: infatti, ho notato questo mentre aggiungo effettivamente il codice ^^ 'Anche se m_value è un membro (quindi dovrebbe funzionare effettivamente), restituendo per valore corregge il mio problema (anche se devo ancora usare lock_guard ). Quello che ho aggiunto è in realtà un problema non realizzato. Grazie. – Korchkidu

risposta

15

Utilizzare un std::lock_guard per gestire il blocco e lo sblocco del mutex tramite RAII, che è letteralmente per che cosa è stato creato.

int foo() 
{ 
    std::lock_guard<std::mutex> lg(some_mutex); // This now locked your mutex 
    for (auto& element : some_vector) 
    { 
     // do vector stuff 
    } 
    return 5; 
} // lg falls out of scope, some_mutex gets unlocked 

Dopo foo rendimenti, lg cadranno fuori portata, e unlocksome_mutex quando lo fa.

+1

Questo è esattamente quello che stavo cercando. Grazie. – Korchkidu

+0

Allora cosa succede se ho qualcosa di simile: auto vec = MyFunc(); operator = potrebbe inserire il vettore restituito da MyFunc() in vec mentre un thread modifica il vettore restituito? – Korchkidu

+0

Quindi sembra che potresti avere un problema di progettazione a cui pensare. È difficile dare una risposta senza vedere un esempio specifico. – CoryKramer

7

Questo è il tipo di domanda con cui le dichiarazioni di stampa possono davvero essere d'aiuto. Per esempio:

#include <mutex> 
#include <iostream> 

std::mutex mut; 

template <class Mutex> 
class Lock 
{ 
    Mutex& mut_; 
public: 
    ~Lock() 
    { 
     std::cout << "unlock\n"; 
     mut_.unlock(); 
    } 

    Lock(const Lock&) = delete; 
    Lock& operator=(const Lock&) = delete; 

    Lock(Mutex& mut) 
     : mut_(mut) 
    { 
     mut_.lock(); 
     std::cout << "lock\n"; 
    } 
}; 

struct A 
{ 
    ~A() 
    { 
     std::cout << "~A() : " << this << "\n"; 
    } 

    A() 
    { 
     std::cout << "A() : " << this << "\n"; 
    } 

    A(const A& a) 
    { 
     std::cout << "A(const A&) : " << this << ", " << &a << "\n"; 
    } 

    A& operator=(const A& a) 
    { 
     std::cout << "A& operator=(const A&) : " << this << ", " << &a << "\n"; 
     return *this; 
    } 
}; 

A a; 

A 
get() 
{ 
    Lock<std::mutex> lk(mut); 
    return a; 
} 

int 
main() 
{ 
    std::cout << "Start\n"; 
    auto vec = get(); 
    std::cout << "End\n"; 
} 

Rendendo la mia versione di std::lock_guard, posso inserire istruzioni di stampa per sapere quando il mutex viene bloccato e sbloccato. .

e facendo un falso std::vector (chiamato A sopra), posso inserire le dichiarazioni di stampa nel membri speciali che mi interessano per me questo uscite:

A() : 0x10fcfb188 
Start 
lock 
A(const A&) : 0x7fff4ff06b28, 0x10fcfb188 
unlock 
End 
~A() : 0x7fff4ff06b28 
~A() : 0x10fcfb188 

che dimostra chiaramente che il mutex è bloccato mentre viene copiato il A a 0x10fcfb188.

Il test può essere modificato per l'assegnazione con:

int 
main() 
{ 
    A vec; 
    std::cout << "Start\n"; 
    vec = get(); 
    std::cout << "End\n"; 
} 

che ora uscite:

A() : 0x10d8a7190 
A() : 0x7fff5235ab28 
Start 
lock 
A(const A&) : 0x7fff5235ab18, 0x10d8a7190 
unlock 
A& operator=(const A&) : 0x7fff5235ab28, 0x7fff5235ab18 
~A() : 0x7fff5235ab18 
End 
~A() : 0x7fff5235ab28 
~A() : 0x10d8a7190 

Dapprima sembra che l'assegnazione avviene al di fuori del blocco, e quindi sembra pericoloso. Tuttavia, a seguito di un'ispezione più ravvicinata, si vede che lo A protetto a 0x10d8a7190 viene copiato in uno spazio temporaneo A all'interno del blocco. Il mutex viene quindi sbloccato e viene assegnato un incarico dal temporaneo al locale. Nessun altro thread potrebbe fare riferimento al temporaneo. Quindi, fino a quando nessun altro thread fa riferimento a vec, questo è di nuovo sicuro.

+0

Davvero una bella spiegazione. Grazie! – Korchkidu

Problemi correlati