std:: unique lock czy STD::lock guard?

Mam dwa przypadki użycia.

A. chcę zsynchronizować dostęp przez dwa wątki do kolejki.

B. chcę zsynchronizować dostęp przez dwa wątki do kolejki i użyć zmiennej warunkowej, ponieważ jeden z wątków będzie czekał na zawartość, która zostanie zapisana do kolejki przez drugi wątek.

W przypadku użycia a widzę przykład kodu z użyciem std::lock_guard<>. W przypadku użycia B widzę przykład kodu przy użyciu std::unique_lock<>.

Jaka jest różnica między tymi dwoma a tym, który z nich powinien Używam w jakim przypadku użycia?

Author: Guy Avraham, 2013-12-11

5 answers

Różnica polega na tym, że możesz zablokować i odblokować std::unique_lock. std::lock_guard zostanie zablokowany tylko raz na budowie i odblokowany po zniszczeniu.

Więc dla przypadku użycia B zdecydowanie potrzebujesz std::unique_lock dla zmiennej warunkowej. W przypadku A to zależy, czy trzeba ponownie zablokować strażnika.

std::unique_lock posiada inne funkcje, które pozwalają na np.: być skonstruowane bez natychmiastowego blokowania mutex, ale aby zbudować wrapper RAII (zobacz tutaj ).

std::lock_guard zapewnia również wygodny wrapper RAII, ale nie może bezpiecznie zablokować wielu muteksów. Może być używany, gdy potrzebujesz wrappera o ograniczonym zakresie, np.: a member function:

class MyClass{
    std::mutex my_mutex;
    void member_foo() {
        std::lock_guard<mutex_type> lock(this->my_mutex);            
        /*
         block of code which needs mutual exclusion (e.g. open the same 
         file in multiple threads).
        */

        //mutex is automatically released when lock goes out of scope           
};

Aby wyjaśnić pytanie przez chmike, domyślnie std::lock_guard i std::unique_lock są takie same. Tak więc w powyższym przypadku, można zastąpić {[2] } std::unique_lock. Jednakże, std::unique_lock może mieć trochę więcej kosztów.

 248
Author: inf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-15 10:14:14

lock_guard i {[1] } są prawie to samo; lock_guard jest wersją ograniczoną z ograniczonym interfejsem.

A lock_guard zawsze trzyma zamek od jego konstrukcji do zniszczenia. unique_lock może zostać utworzona bez natychmiastowego blokowania, może Odblokować się w dowolnym momencie swojego istnienia i może przenieść własność blokady z jednej instancji do drugiej.

Więc zawsze używasz lock_guard, chyba że potrzebujesz możliwości unique_lock. A condition_variable potrzebuje a unique_lock.

 82
Author: Sebastian Redl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-11 10:41:08

Użyj lock_guard, chyba że musisz być w stanie ręcznie unlock mutex pomiędzy Bez Niszczenia lock.

W szczególności, condition_variable odblokowuje swój mutex, gdy idzie spać na połączenia do wait. Dlatego lock_guard nie wystarcza tutaj.

 34
Author: ComicSansMS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-11 10:39:03

Między lock_guard a unique_lock istnieją pewne wspólne rzeczy i pewne różnice.

Ale w kontekście zadanego pytania kompilator nie zezwala na użycie lock_guard w połączeniu ze zmienną warunkową, ponieważ gdy wątek wywołuje wait na zmiennej warunkowej, mutex zostaje odblokowany automatycznie, a gdy inny wątek/wątki powiadomi i bieżący wątek jest wywoływany( wychodzi z wait), blokada jest odzyskiwana ponownie.

Zjawisko to jest sprzeczne z zasadą lock_guard. lock_guard można zbudować tylko raz i zniszczyć tylko raz.

Stąd lock_guard nie może być używany w połączeniu ze zmienną warunkową, ale unique_lock może być (ponieważ unique_lock może być zablokowany i odblokowany kilka razy).

 8
Author: Sandeep,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-12 18:09:07

Jak już wspomnieli inni, std:: unique_lock śledzi zablokowany status mutex, więc możesz odroczyć blokowanie do czasu zbudowania blokady i odblokować przed zniszczeniem blokady. std:: lock_guard nie pozwala na to.

Nie ma powodu, dla którego funkcje STD::condition_variable wait nie powinny przyjmować lock_guard, jak również unique_lock, ponieważ za każdym razem, gdy kończy się oczekiwanie (z jakiegokolwiek powodu), mutex jest automatycznie ponownie pobierany tak, że nie spowoduje to żadnych naruszenie semantyczne. Jednak zgodnie ze standardem, aby użyć STD:: lock_guard ze zmienną warunkową, musisz użyć std:: condition_variable_any zamiast std::condition_variable.

Edit: deleted "używanie interfejsu pthreads std::condition_variable i std:: condition_variable_any powinno być identyczne". Po przyjrzeniu się implementacji gcc:

  • std:: condition_variable:: wait (STD:: unique_lock&) po prostu wywołuje pthread_cond_wait () na bazowym pthreadzie zmienna warunkowa w odniesieniu do mutex posiadanego przez unique_lock (i tak samo może zrobić to samo dla lock_guard, ale nie, ponieważ standard tego nie przewiduje)
  • std::condition_variable_any może pracować z dowolnym blokowanym obiektem, w tym z takim, który w ogóle nie jest blokadą mutex (może więc pracować nawet z semaforem między procesami)
 -6
Author: Chris Vine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-18 11:51:20