534 Stimmen

<std::unique_lock<std::mutex>> oder <std::lock_guard<std::mutex>> ?

Ich habe zwei Anwendungsfälle.

A. Ich möchte den Zugriff auf eine Warteschlange für zwei Threads synchronisieren.

B. Ich möchte den Zugriff auf eine Warteschlange für zwei Threads synchronisieren und eine Bedingungsvariable verwenden, da einer der Threads darauf wartet, dass der andere Thread Inhalte in die Warteschlange speichert.

Für Anwendungsfall A sehe ich einen Code-Beispiel, das std::lock_guard<> verwendet. Für Anwendungsfall B sehe ich einen Code-Beispiel, das std::unique_lock<> verwendet.

Was ist der Unterschied zwischen den beiden und welche sollte ich für welchen Anwendungsfall verwenden?

-2voto

rekkalmd Punkte 143

Sie sind nicht wirklich die gleichen Mutexe, lock_guard hat fast das gleiche wie std::mutex, mit dem Unterschied, dass sein Lebensdauer am Ende des Gültigkeitsbereichs endet (D-Tor aufgerufen wurde), daher eine klare Definition dieser beiden Mutexe :

lock_guard verfügt über einen Mechanismus zum Besitzen eines Mutex für die Dauer eines begrenzten Blocks.

Und

unique_lock ist ein Wrapper, der das verzögerte Sperren, zeitbeschränkte Versuche des Sperrens, rekursives Sperren, Übertragung des Besitzes des Schlosses und die Verwendung mit bedingten Variablen ermöglicht.

Hier ist ein Beispiel für die Implementierung:

#include 
#include 
#include 
#include 
#include 
#include 

using namespace std::chrono;

class Produkt{

   public:

       Produkt(int daten):mdata(data){
       }

       virtual~Produkt(){
       }

       bool istBereit(){
       return flag;
       }

       void datenZeigen(){

        std::cout< guard(mmutex);

         flag = true;

         std::cout<<"Daten sind bereit"< sperre(mmutex);

       cvar.wait(sperre, [&, this]() mutable throw() -> bool{ return this->istBereit(); });

       mdata+=1;

       }

   protected:

    std::condition_variable cvar;
    std::mutex mmutex;
    int mdata;
    bool flag = false;

};

int main(){

     int a = 0;
     Produkt produkt(a);

     std::thread lesen(produkt.lesen, &produkt);
     std::thread einstellen(produkt.aufgabe, &produkt);

     lesen.join();
     einstellen.join();

     produkt.datenZeigen();
    return 0;
}

In diesem Beispiel habe ich unique_lock mit Bedingungsvariable verwendet

-5voto

Chris Vine Punkte 612

Wie bereits von anderen erwähnt wurde, verfolgt std::unique_lock den gesperrten Status des Mutex, sodass Sie das Sperren bis nach der Konstruktion des Locks verschieben und vor der Zerstörung des Locks freigeben können. std::lock_guard ermöglicht dies nicht.

Es scheint keinen Grund dafür zu geben, warum die Wartefunktionen von std::condition_variable nicht auch einen lock_guard anstelle eines unique_lock akzeptieren sollten, denn wann immer eine Wartezeit endet (aus welchem Grund auch immer) wird der Mutex automatisch wieder erworben, sodass dies keinen semantischen Verstoß verursachen würde. Gemäß dem Standard müssen Sie jedoch eine std::condition_variable_any anstelle von std::condition_variable verwenden, um einen std::lock_guard mit einer Bedingungsvariable zu verwenden.

Bearbeiten: "Mit der pthreads-Schnittstelle sollten std::condition_variable und std::condition_variable_any identisch sein." wurde gelöscht. Beim Betrachten der Implementierung von gcc:

  • std::condition_variable::wait(std::unique_lock&) ruft einfach pthread_cond_wait() auf der zugrunde liegenden pthread-Bedingungsvariable unter Berücksichtigung des Mutex auf, der von unique_lock gehalten wird (und könnte dasselbe auch für lock_guard tun, tut es aber nicht, weil der Standard das nicht vorsieht)
  • std::condition_variable_any kann mit einem beliebigen sperrbaren Objekt arbeiten, einschließlich eines, das überhaupt keine Mutexsperrung ist (es könnte daher sogar mit einem interprozessualen Semaphore funktionieren)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X