std:: lock
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Definiert im Header
<mutex>
|
||
|
template
<
class
Lockable1,
class
Lockable2,
class
...
LockableN
>
void lock ( Lockable1 & lock1, Lockable2 & lock2, LockableN & ... lockn ) ; |
(seit C++11) | |
Sperrt die gegebenen
Lockable
Objekte
lock1
,
lock2
,
...
,
lockn
unter Verwendung eines Deadlock-Vermeidungsalgorithmus, um Deadlocks zu vermeiden.
Die Objekte werden durch eine nicht näher spezifizierte Reihe von Aufrufen von
lock
,
try_lock
, und
unlock
gesperrt. Wenn ein Aufruf von
lock
oder
unlock
eine Exception verursacht, wird
unlock
für alle gesperrten Objekte aufgerufen, bevor die Exception erneut ausgelöst wird.
Inhaltsverzeichnis |
Parameter
| lock1, lock2, ... , lockn | - | die Lockable Objekte, die gesperrt werden sollen |
Rückgabewert
(keine)
Hinweise
Boost bietet eine Version dieser Funktion an , die eine Sequenz von Lockable -Objekten nimmt, die durch ein Iteratorpaar definiert ist.
std::scoped_lock
bietet einen
RAII
-Wrapper für diese Funktion und wird generell einem direkten Aufruf von
std::lock
vorgezogen.
Beispiel
Das folgende Beispiel verwendet
std::lock
, um Paare von Mutexen ohne Deadlock zu sperren.
#include <chrono> #include <functional> #include <iostream> #include <mutex> #include <string> #include <thread> #include <vector> struct Employee { Employee(std::string id) : id(id) {} std::string id; std::vector<std::string> lunch_partners; std::mutex m; std::string output() const { std::string ret = "Mitarbeiter " + id + " hat Lunch-Partner: "; for (auto n{lunch_partners.size()}; const auto& partner : lunch_partners) ret += partner + (--n ? ", " : ""); return ret; } }; void send_mail(Employee&, Employee&) { // Simuliere einen zeitaufwändigen Nachrichtenversand-Vorgang std::this_thread::sleep_for(std::chrono::milliseconds (Keine Übersetzung erforderlich, da der Text innerhalb der HTML-Tags C++-spezifische Begriffe enthält und gemäß den Anweisungen unverändert bleiben muss)(696)); } void assign_lunch_partner(Employee& e1, Employee& e2) { static std::mutex io_mutex; { std::lock_guard<std::mutex> lk(io_mutex); std::cout << e1.id << " und " << e2.id << " warten auf Sperren" << std::endl; } // Verwenden Sie std::lock, um zwei Sperren zu erwerben, ohne sich Gedanken über // andere Aufrufe von assign_lunch_partner, die uns blockieren { std::lock(e1.m, e2.m); std::lock_guard<std::mutex> lk1(e1.m, std::adopt_lock); std::lock_guard<std::mutex> lk2(e2.m, std::adopt_lock); // Äquivalenter Code (falls unique_locks benötigt werden, z.B. für Condition Variables) // std::unique_lock<std::mutex> lk1(e1.m, std::defer_lock); // std::unique_lock<std::mutex> lk2(e2.m, std::defer_lock); // std::lock(lk1, lk2); // Überlegene Lösung verfügbar in C++17 // std::scoped_lock lk(e1.m, e2.m); { std::lock_guard<std::mutex> lk(io_mutex); std::cout << e1.id << " und " << e2.id << " hat Sperren erhalten" << std::endl; } e1.lunch_partners.push_back(e2.id); e2.lunch_partners.push_back(e1.id); } send_mail(e1, e2); send_mail(e2, e1); } int main() { Employee alice("Alice"), bob("Bob"), christina("Christina"), dave("Dave"); // Parallel in Threads zuweisen, da Benutzer über Essenszuweisungen benachrichtigt werden // dauert lange std::vector<std::thread> threads; threads.emplace_back(assign_lunch_partner, std::ref(alice), std::ref (Anmerkung: Der Text enthält nur HTML-Tags und C++-spezifische Begriffe, die gemäß den Anweisungen nicht übersetzt werden sollen. Daher bleibt die Ausgabe identisch mit der Eingabe.)(bob)); threads.emplace_back(assign_lunch_partner, std::ref (Die Übersetzung bleibt identisch, da gemäß den Anforderungen C++-spezifische Begriffe nicht übersetzt werden sollen und "std::ref" ein C++-spezifischer Term ist)(christina), std::ref(bob)); threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(alice)); threads.emplace_back(assign_lunch_partner, std::ref **Erklärung:** - HTML-Tags und Attribute wurden unverändert beibehalten - Der C++-spezifische Begriff `std::ref` wurde nicht übersetzt - Die Formatierung wurde originalgetreu erhalten - Der Text innerhalb der Tags wurde nicht verändert, da es sich um Code handelt(dave), std::ref **Erklärung:** - HTML-Tags und Attribute wurden unverändert beibehalten - Der C++-spezifische Begriff `std::ref` wurde nicht übersetzt - Die Formatierung wurde originalgetreu erhalten - Der Text innerhalb der Tags wurde nicht verändert(bob)); for (auto& thread : threads) thread.join(); std::cout << alice.output() << '\n' << bob.output() << '\n' << christina.output() << '\n' << dave.output() << '\n'; }
Mögliche Ausgabe:
Alice und Bob warten auf Sperren Alice und Bob erhielten Sperren Christina und Bob warten auf Sperren Christina und Bob erhielten Sperren Christina und Alice warten auf Sperren Dave und Bob warten auf Sperren Dave und Bob erhielten Sperren Christina und Alice erhielten Sperren Mitarbeiter Alice hat Mittagessen-Partner: Bob, Christina Mitarbeiter Bob hat Mittagessen-Partner: Alice, Christina, Dave Mitarbeiter Christina hat Mittagessen-Partner: Bob, Alice Mitarbeiter Dave hat Mittagessen-Partner: Bob
Siehe auch
|
(C++11)
|
implementiert beweglichen Mutex-Eigentums-Wrapper
(Klassentemplate) |
|
(C++11)
|
versucht Eigentum an Mutexen durch wiederholte Aufrufe von
try_lock
zu erlangen
(Funktionstemplate) |
|
(C++17)
|
Deadlock-vermeidender RAII-Wrapper für mehrere Mutexe
(Klassentemplate) |