Classe scoped_lock

La scoped_lock classe acquisisce uno o più mutex sulla costruzione e li rilascia alla distruzione. Quando vengono forniti più mutex, viene usato un algoritmo di prevenzione del deadlock (equivalente a std::lock) per evitare deadlock. Introdotto in C++17.

Sintassi


// Single mutex type version
template <class _Mutex>
class _NODISCARD_LOCK scoped_lock<_Mutex> {
public:
    using mutex_type = _Mutex;

    explicit scoped_lock(_Mutex& _Mtx) : _MyMutex(_Mtx) { // construct and lock
        _MyMutex.lock();
    }

    explicit scoped_lock(adopt_lock_t, _Mutex& _Mtx) noexcept
        : _MyMutex(_Mtx) {} // construct but don't lock

    ~scoped_lock() noexcept {
        _MyMutex.unlock();
    }

    scoped_lock(const scoped_lock&)            = delete; // prevent creating a new scoped_lock by copying an existing one
    scoped_lock& operator=(const scoped_lock&) = delete; // prevent assigning one scoped_lock to another
};

// multiple mutex types version
template <class... MutexTypes>
class scoped_lock {
    explicit scoped_lock(MutexTypes&... m);
    explicit scoped_lock(MutexTypes&... m, adopt_lock_t);
    ~scoped_lock();
    scoped_lock(const scoped_lock&) = delete; // prevent creating a new scoped_lock by copying an existing one
    scoped_lock& operator=(const scoped_lock&) = delete; // prevent assigning one scoped_lock to another
};

Osservazioni:

adopt_lock_t è un tipo di tag che indica che il costruttore deve assumere la scoped_lock proprietà dei mutex già bloccati dal thread chiamante. In questo modo è possibile creare un scoped_lock oggetto senza bloccare nuovamente i mutex, che possono essere utili in determinati scenari in cui sono già stati acquisiti i blocchi e si vuole gestire la durata con un oggetto scoped_lock.

La scoped_lock classe gestisce il blocco e lo sblocco di uno o più mutex in un ambito. Quando si crea un scoped_lock oggetto, acquisisce la proprietà dei mutex passati. Quando l'oggetto scoped_lock viene eliminato definitivamente (ad esempio, quando esce dall'ambito), i mutex vengono rilasciati. In questo modo, i mutex vengono sempre rilasciati correttamente, anche se viene generata un'eccezione.

Se è necessario bloccare solo un singolo mutex, è consigliabile usare lock_guard o unique_lock. Usare scoped_lock quando è necessario bloccare più mutex contemporaneamente senza rischi di deadlock.

La scoped_lock classe non è copiabile.

Se viene passato un solo tipo mutex a scoped_lock, scoped_lock fornisce un alias di tipo denominato mutex_type che fa riferimento a quel tipo mutex. Tuttavia, se si crea un scoped_lock oggetto con due o più tipi mutex, l'alias mutex_type non esiste perché mutex_type ha senso solo quando è presente un singolo tipo mutex sottostante. Con più mutex, non esiste un tipo mutex da esporre.

Costruttori

Costruttore Descrizione
scoped_lock(MutexTypes&... m) Costruisce un scoped_lock oggetto e blocca tutti i mutex forniti. Se vengono forniti più mutex, questi vengono bloccati usando un algoritmo di prevenzione dei deadlock.
scoped_lock(MutexTypes&... m, adopt_lock_t) Costruisce un scoped_lock oggetto e adotta la proprietà dei mutex forniti, che devono essere già bloccati dal thread chiamante.

Distruttore

Distruttore Descrizione
~scoped_lock() Elimina l'oggetto scoped_lock e rilascia tutti i mutex di proprietà.

Esempio

#include <iostream>
#include <mutex>
#include <thread>
#include <vector>

std::mutex mutex1;
std::mutex mutex2;
int shared_data1 = 0;
int shared_data2 = 0;

void update_both(int iterations)
{
    for (int i = 0; i < iterations; ++i)
    {
        // Lock both mutexes simultaneously without risk of deadlock
        std::scoped_lock lock(mutex1, mutex2);
        ++shared_data1;
        ++shared_data2;
    }
}

int main()
{
    std::vector<std::thread> threads;
    for (int i = 0; i < 4; ++i)
    {
        threads.emplace_back(update_both, 1000);
    }

    for (auto& t : threads)
    {
        t.join();
    }

    std::cout << "shared_data1: " << shared_data1 << '\n';
    std::cout << "shared_data2: " << shared_data2 << '\n';
    // Output:
    // shared_data1: 4000
    // shared_data2: 4000
}

Requisiti

Intestazione:<mutex>

Spazio dei nomi:std

Vedere anche

lock_guard classe
unique_lock classe
<mutex>