Namensräume
Varianten
Aktionen

std::scoped_lock

Von cppreference.com
< cpp‎ | thread
 
 
Bibliothek für nebenläufige Programmierung
Threads
(C++11)
(C++20)
this_thread Namespace
(C++11)
(C++11)
(C++11)
Kooperatives Beenden
Gegenseitiger Ausschluss
(C++11)
Allgemeines Sperrungsmanagement
(C++11)
(C++11)
scoped_lock
(C++17)
(C++11)
(C++11)
(C++11)
Bedingungsvariablen
(C++11)
Semaphoren
Latches und Barriers
(C++20)
(C++20)
Futures
(C++11)
(C++11)
(C++11)
(C++11)
Sichere Wiederherstellung
(C++26)
Hazard Pointer
Atomare Typen
(C++11)
(C++20)
Initialisierung von atomaren Typen
(C++11)(veraltet in C++20)
(C++11)(veraltet in C++20)
Speicherordnung
(C++11)(deprecated in C++26)
Freie Funktionen für atomare Operationen
Freie Funktionen für atomare Flags
 
 
Definiert in Header <mutex>
template< class... MutexTypes >
class scoped_lock;
(seit C++17)

Die Klasse scoped_lock ist ein Mutex-Wrapper, der einen bequemen RAII-Stil Mechanismus für den Besitz von null oder mehr Mutexen für die Dauer eines gesperrten Blocks bietet.

Wenn ein scoped_lock Objekt erstellt wird, versucht es, den Besitz der übergebenen Mutexe zu erlangen. Wenn die Kontrolle den Gültigkeitsbereich verlässt, in dem das scoped_lock Objekt erstellt wurde, wird das scoped_lock zerstört und die Mutexe werden freigegeben. Wenn mehrere Mutexe übergeben werden, wird ein Algorithmus zur Vermeidung von Deadlocks verwendet, als ob er von std::lock stammen würde.

Die Klasse scoped_lock ist nicht kopierbar.

Inhalt

[bearbeiten] Template-Parameter

MutexTypes - die Typen der zu sperrenden Mutexe. Die Typen müssen die Lockable Anforderungen erfüllen, es sei denn, sizeof...(MutexTypes) == 1, in diesem Fall muss der einzige Typ BasicLockable erfüllen.

[bearbeiten] Member-Typen

Mitgliedertyp Definition
mutex_type
(bedingt vorhanden)

Wenn sizeof...(MutexTypes) == 1, ist der Member-Typ mutex_type derselbe wie Mutex, der einzige Typ in MutexTypes.... Andernfalls gibt es kein Member mutex_type.

[bearbeiten] Member-Funktionen

konstruiert ein scoped_lock, optional sperrt die gegebenen Mutexe
(öffentliche Member-Funktion) [bearbeiten]
zerstört das scoped_lock Objekt, gibt die zugrunde liegenden Mutexe frei
(öffentliche Member-Funktion) [bearbeiten]
operator=
[gelöscht]
nicht kopierbar
(öffentliche Member-Funktion) [bearbeiten]

[bearbeiten] Hinweise

Ein häufiger Anfängerfehler ist es, einer scoped_lock Variablen einen Namen zu "vergessen", z.B. std::scoped_lock(mtx); (was eine scoped_lock Variable namens mtx standardmäßig konstruiert) oder std::scoped_lock{mtx}; (was ein prvalue-Objekt konstruiert, das sofort zerstört wird), wodurch kein Lock erstellt wird, das einen Mutex für den Rest des Gültigkeitsbereichs hält.

Feature-Test-Makro Wert Std Feature
__cpp_lib_scoped_lock 201703L (C++17) std::scoped_lock

[bearbeiten] Beispiel

Das folgende Beispiel verwendet std::scoped_lock, um Mutex-Paare ohne Deadlock zu sperren und im RAII-Stil zu arbeiten.

#include <chrono>
#include <functional>
#include <iostream>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
using namespace std::chrono_literals;
 
struct Employee
{
    std::vector<std::string> lunch_partners;
    std::string id;
    std::mutex m;
    Employee(std::string id) : id(id) {}
    std::string partners() const
    {
        std::string ret = "Employee " + id + " has lunch partners: ";
        for (int count{}; const auto& partner : lunch_partners)
            ret += (count++ ? ", " : "") + partner;
        return ret;
    }
};
 
void send_mail(Employee&, Employee&)
{
    // Simulate a time-consuming messaging operation
    std::this_thread::sleep_for(1s);
}
 
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 << " and " << e2.id << " are waiting for locks" << std::endl;
    }
 
    {
        // Use std::scoped_lock to acquire two locks without worrying about
        // other calls to assign_lunch_partner deadlocking us
        // and it also provides a convenient RAII-style mechanism
 
        std::scoped_lock lock(e1.m, e2.m);
 
        // Equivalent code 1 (using std::lock and std::lock_guard)
        // 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);
 
        // Equivalent code 2 (if unique_locks are needed, e.g. for 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);
        {
            std::lock_guard<std::mutex> lk(io_mutex);
            std::cout << e1.id << " and " << e2.id << " got locks" << 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");
 
    // Assign in parallel threads because mailing users about lunch assignments
    // takes a long time
    std::vector<std::thread> threads;
    threads.emplace_back(assign_lunch_partner, std::ref(alice), std::ref(bob));
    threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(bob));
    threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(alice));
    threads.emplace_back(assign_lunch_partner, std::ref(dave), std::ref(bob));
 
    for (auto& thread : threads)
        thread.join();
    std::cout << alice.partners() << '\n'  << bob.partners() << '\n'
              << christina.partners() << '\n' << dave.partners() << '\n';
}

Mögliche Ausgabe

Alice and Bob are waiting for locks
Alice and Bob got locks
Christina and Bob are waiting for locks
Christina and Alice are waiting for locks
Dave and Bob are waiting for locks
Dave and Bob got locks
Christina and Alice got locks
Christina and Bob got locks
Employee Alice has lunch partners: Bob, Christina
Employee Bob has lunch partners: Alice, Dave, Christina
Employee Christina has lunch partners: Alice, Bob
Employee Dave has lunch partners: Bob

[bearbeiten] Fehlerberichte

Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR angewendet auf Verhalten wie veröffentlicht Korrigiertes Verhalten
LWG 2981 C++17 Ein redundanter Ableitungsführer von scoped_lock<MutexTypes...> wurde bereitgestellt entfernt

[bearbeiten] Siehe auch

implementiert verschiebbaren Mutex-Besitz-Wrapper
(Klassenvorlage) [bearbeiten]
implementiert einen streng bereichsbezogenen Mutex-Besitz-Wrapper
(Klassen-Template) [bearbeiten]