Unsere Datenschutzrichtlinie wird in Kürze aktualisiert. Bitte sehen Sie sich die Vorschau an.

C++: Multithreading

std::unique_lock

Testen Sie unsere 2016 Kurse

10 Tage kostenlos!

Jetzt testen Alle Abonnements anzeigen
std::unique_lock ist für den anspruchsvollen Anwendungsfall konzipiert. So kann er zum Beispiel seinen Mutex versuchsweise oder verzögert locken.
08:37

Transkript

In dieser Lektion möchte ich Ihnen unique_lock vorstellen. Der unique_lock ist der große Bruder des lockGuards und bietet als sein großer Bruder ein deutlich mächtigeres Interface an. Zusätzlich gibt es in C++ 14 die sogenannten Reader-Writer-Locks. Diese Locks haben das Interface des unique_locks, bieten aber noch weitere Möglichkeiten an. Der Standard-unique_lock ist für den anspruchsvollen Anwendungsfall konzipiert. Das heißt, er ist in der Regel auch ein bisschen teurer wie der lockGuard. Was kann er denn alles? Er kann einiges: Er kann ohne einen Mutex oder einen Mutex, der nicht gelockt ist, erzeugt werden. Er kann explizit, auch wiederholt ein Lock setzen und freigeben, also lock und unlock aufrufen, ungelockten Mutex in einen anderen std: :unique_lock verschieben - das ist die sogenannte Move Semantic. Er kann testen, ob ein Lock einen Mutex besitzt, er kann auch zeitlich verzögert locken. Und das können Sie auch mit absoluter oder relativer Zeitangabe tun. Und Sie können mit standard swap unique_locks tauschen. Das Interface schau ich mir mit Ihnen gern nochmals im Detail an. Durch lk.lock locken Sie den assoziierten Mutex. Durch lk.unlock unlocken Sie ihn. Jetzt kommen die Versionen, in denen Sie nur versuchen, den Mutex zu locken. Das können Sie durch try_lock machen, oder Sie können es auch durch try_lock, indem Sie eine relative oder absolute Zeitangabe mitgeben. Das heißt, bei der relativen Zeitangabe geben Sie eine Zeit auch mit. Bei absoluter Zeitangabe geben Sie einen Zeitpunkt mit. Mit release geben Sie den Mutex frei, der Lock wird aber nicht freigegeben. Das heißt, lk.release gibt Ihnen den Mutex zurück, und Sie müssen natürlich dann den Mutex annehmen. Mit swap tauschen Sie Locks von Mutexen. Durch den Aufruf lk.mutex bekommen Sie einen Zeiger auf den assoziierten Mutex zurück. Mit owns_lock können Sie fragen, ob der Lock einen Mutex besitzt. Und jetzt kommt eine sehr interessante Funktion: std: : lock von lk1, lk2, … - ist 'ne Funktion, eine globale Funktion, die es Ihnen erlaubt, in einer atomaren Weise, ich will es explizit gern nochmals betonen, in einer atomaren Weise viele Mutexe, beliebig viele Mutexe in einem Schritt zu locken, oder auch nicht: je nachdem, ob es geklappt hat. std: : lock versucht also, alle Mutexe in einem atomaren Schritt zu locken. Und wenn es geklappt hat - okay. Wenn net - wird's natürlich wiederholt. Zum Schluss noch den sogenannten std: :shared_lock, den Sie in Kombination mit dem std: :shared_timed_mutex verwenden können. Es kann natürlich sein, dass Sie diese Funktionalität noch nicht auf Ihrer Plattform haben. Um das zu verwenden, benötigen Sie neuen Gate CC, oder einen relativ neuen Clang Compiler. Microsoft Visual C++15 unterstützt nicht C++14. Gut, was können Sie mit dem std: :shared_lock machen? Mit dem std: :shared_lock können Sie Reader-Writer-Locks implementieren. Was heißt es? Sie implementieren Locks, die unterscheiden können, ob Sie auf Ihre kritische Variable lesend oder schreibend zugreifen. Sie können ohne weiteres mit beliebig vielen Threads gleichzeitig lesend auf eine Variable zugreifen. Das können Sie erlauben. Es darf aber immer nur eine genau schreiben. Und das können Sie mit Reader-Writer-Locks implementieren. Viele dürfen gleichzeitig lesen, aber nur eine darf schreiben. Und nun komme ich zur Praxis und stelle Ihnen unique_lock genau vor. In diesem Beispiel verwende ich 'nen unique_lock: hier und hier, verwende den aber bewusst falsch und zeige Ihnen dann, wie Sie das Problem dadurch lösen, dass Sie das mächtigere Interface von unique_lock verwenden. Erstmal zum Problem! Hier habe ich CriticalData. Das sind die kritischen Daten oder der kritische Bereich, den ich schützen will. Drunter verwende ich intern hier mutex. Okay. Dann, was mache ich hier? Hier habe ich diese thread t1, der führt die Funktion "deadLock" aus, verwendet CriticalData c1 und c2 per Referenz Landefunktion, und hier per Referenz deadLock 2. Ist die gleiche Funktion, verwendet aber c2 und c1 in verschiedener Reihenfolge. Und jetzt schauen wir uns deadLock genau an: deadLock(CriticalData& a, CriticalData& b) Sehr entscheidend ist das hier, hier und hier. Hier locke ich den mutex (a.mut) in einem unique_lock Ich lock den im Konstruktoraufruf von guard1. Das gleiche tue ich hier mit guard2. Und mein Problem ist natürlich, dass ich die Mutexe in verschiedener Reihenfolge locke: c1, ca - c2, c1 Allein durch das Schlafen hier von einer Millisekunde wird's passieren, dass erst thread1 (a.mut) zieht, dann thread2 (b.mut) zieht. Ich rufe ja die Mutexe in verschiedener Reihenfolge auf. Und dann versucht a.mut den anderen Mutex zu ziehen, kann aber nicht mehr, weil der bereits durch einen anderen Thread gezogen ist, sprich gelockt. Tue ich ein einfaches Rezept, um deadLock zu fabrizieren, und das zeige ich Ihnen. Und Sie sehen genau das, was ich beschrieben hab: this_thread: :get_id Der erste Thread kommt zum Zuge. Der ID endet auf 32. Der zweite Thread kommt zum Zuge. Der ID endet auf 28. Und keiner kommt an diese Stelle hier, weil er den Mutex benötigt, den der andere Thread bereits gelockt hat. Hm… Was macht mal da? Ich zeige Ihnen gleich die Lösung. Schauen Sie hier: deadlockResolved Was ich mache, ist - ich tipp…. Sie haben gesehen, ich muss das Programm wirklich abbrechen. Ein deadLock bedeutet, es geht nichts mehr. Ich muss das Programm abbrechen, sprich - den Prozess abschießen. Was mache ich hier? Drei Veränderungen: Erstens, ich sag zum unique_lock: ziehe den Mutex nicht sofort, sondern ziehe ihn verzögert. Das heißt, durch diesen Aufruf bekommt der guard1 zwar den Mutex, aber er lockt ihn nicht im Konstruktor. Das gleiche mache ich hier: guard 2 ist nun der Besitzer von b.mut, aber er lockt den Mutex b.mut nicht genau an dieser Stelle hier. Wann geschieht das Locken? Genau hier: das ist eine entscheidende Zeile. Hier wird versucht, beide Mutexe in einer atomaren Weise zu locken. Klappt es - ist okay! Wenn nicht - findet hier eine Iteration statt. Ich würd' sagen, jetzt schau ich mir doch die Lösung an. Und Sie sehen, diesmal läuft das Programm durch. Es ist kein deadLock. Und jetzt können wir schon in der Ausgabe nachverfolgen, welcher Thread wann zum Zuge kommt. Jetzt kommt der erste Thread zum Zuge, dann kommt der zweite Thread zum Zuge. Das sind die Thread-IDs. Dann kommt der zweite Thread 04, 04 dazu, den second mutex zu besitzen. Er lockt nicht, er ist nur der Besitzer des second mutex. Das ist genau die Zeile hier. Hier ist die entscheidende Ausgabe. Jetzt gelingt es dem zweiten Thread, die Mutexe atomar zu locken. Er gelangt genau hierher. Ja, und dann ist er mit seiner Arbeit, die relativ kurz ist, fertig. Dann kommt der erste Thread zum Zuge, und zieht den zweiten Mutex 08. Sie sehen es, er stehlt 08 von hier oben. Ja, dann ist er hier auch fertig. In dieser Lektion habe ich Ihnen gezeigt, ein unique_lock ist in der Anwendung teurer als ein lockGuard. Aber Sie haben ein mächtiges Interface, um z.B. wie in dem konkreten Beispiel gezeigt, Mutexe verzögert zu locken.

C++: Multithreading

Lernen Sie die High-Level Threading-Schnittstelle in C++ kennenb und nutzen, die Sie in Form von Threads, Tasks, Locks und Bedingungsvariablen zur Anwendung bringen.

2 Std. 40 min (39 Videos)
Derzeit sind keine Feedbacks vorhanden...
 
Software:
Exklusiv für Abo-Kunden
Erscheinungsdatum:16.08.2016

Dieser Online-Kurs ist als Download und als Streaming-Video verfügbar. Die gute Nachricht: Sie müssen sich nicht entscheiden - sobald Sie das Training erwerben, erhalten Sie Zugang zu beiden Optionen!

Der Download ermöglicht Ihnen die Offline-Nutzung des Trainings und bietet die Vorteile einer benutzerfreundlichen Abspielumgebung. Wenn Sie an verschiedenen Computern arbeiten, oder nicht den ganzen Kurs auf einmal herunterladen möchten, loggen Sie sich auf dieser Seite ein, um alle Videos des Trainings als Streaming-Video anzusehen.

Wir hoffen, dass Sie viel Freude und Erfolg mit diesem Video-Training haben werden. Falls Sie irgendwelche Fragen haben, zögern Sie nicht uns zu kontaktieren!