2014-12-09 17 views
8

Chcę zwrócić std::vector. Ten std::vector może być dostępny z innych wątków (odczyt i zapis). Jak mogę odblokować mój std::mutex zaraz po powrocie funkcji?Jak std :: mutex :: lock until function zwraca

Na przykład coś takiego:

// 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(); 

Teraz co jeśli "Czy Super inteligentne rzeczy tutaj" jest pusta:

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

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

Wtedy to zamek nadal obowiązkowe? Czemu?

+1

Kopiowanie konstrukcji 'vec' odbywa się poza blokadą. Jeśli inne wątki mogłyby modyfikować wektor referencyjny, masz wyścig danych. – Casey

+0

To nie zadziała, zwracasz jakiś stan wewnętrzny ('m_value') przez odniesienie. –

+0

@ DieterLücking: rzeczywiście, zauważyłem to podczas dodawania kodu właściwie ^^ 'Nawet jeśli m_value jest członkiem (tak powinno działać), zwracanie przez wartość rozwiązuje mój problem (mimo że nadal potrzebuję korzystać z lock_guard ). To, co dodałem, jest rzeczywiście nierealnym problemem. Dzięki. – Korchkidu

Odpowiedz

15

Użyj std::lock_guard do obsługi blokowania i odblokowywania mutex przez RAII, czyli dosłownie, do czego został stworzony.

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 

Po foo powraca, lg spadnie poza zakresem, a unlocksome_mutex kiedy to robi.

+1

To jest dokładnie to, czego szukałem. Dzięki. – Korchkidu

+0

A co jeśli mam coś takiego: auto vec = MyFunc(); operator = mógłby wstawić zwrócony wektor z MyFunc() do vec, podczas gdy wątek modyfikuje zwracany wektor? – Korchkidu

+0

Wygląda na to, że możesz mieć problem z projektowaniem. Trudno podać odpowiedź, nie widząc konkretnego przykładu. – CoryKramer

7

Jest to rodzaj pytania, na które instrukcje drukowania mogą naprawdę pomóc. Na przykład:

#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"; 
} 

dokonując własną wersję std::lock_guard mogę wstawić sprawozdań z tuszem, aby dowiedzieć się, kiedy mutex zostanie zablokowane i odblokowane. .

I poprzez fałszywy std::vector (tzw A powyżej), mogę wstawić sprawozdań z tuszem do specjalnego członków, że jestem zainteresowany Dla mnie to wyjścia:

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

który wyraźnie pokazuje, że mutex jest zablokowany podczas kopiowania A z 0x10fcfb188.

Test może być zmienione dla funkcja:

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

które obecnie wyjść:

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 

Na pierwszy rzut oka wydaje się jak następuje przypisanie zewnątrz zamka, a więc wygląda na niebezpieczne. Jednak po bliższej inspekcji widzi się, że chroniony A przy 0x10d8a7190 jest kopiowany do tymczasowego A wewnątrz zamka. Muteks zostanie odblokowany, a zadanie zostanie zmienione z tymczasowego na lokalne. Żaden inny wątek nie mógłby odwoływać się do tymczasowego. Tak długo jak żaden inny wątek nie odwołuje się do vec, jest to znów bezpieczne.

+0

Naprawdę ładne wyjaśnienie. Dzięki! – Korchkidu

Powiązane problemy