Ce face std::scoped_lock
std::scoped_lock este ca std::lock_guard, dar primește oricâte mutexuri. Le ocupă pe toate folosind un algoritm care evită blocajul reciproc (deadlock), indiferent în ce ordine le scrii, și le eliberează la ieșirea din bloc.
Exemplul clasic este transferul între două conturi: fiecare cont are mutexul lui, iar transferul trebuie să le țină pe amândouă. Dacă un fir transferă A→B și altul B→A, ocuparea manuală în ordine diferită poate bloca ambele fire pentru totdeauna.
Cu un singur mutex, std::scoped_lock se comportă exact ca std::lock_guard, așa că mulți îl folosesc peste tot.
Parametri
| Parametru | Descriere |
|---|---|
m1, m2, ... |
Mutexurile ocupate împreună. |
Ce returnează
Un obiect care ține toate mutexurile ocupate cât timp există.
Exemple
Exemplul 1: Transferuri în ambele sensuri
Două fire fac transferuri în sensuri opuse în același timp. Totalul de bani rămâne mereu același.
#include <mutex>
#include <print>
#include <thread>
struct Cont {
std::mutex m;
int sold;
};
void transfera(Cont& din, Cont& in, int suma) {
std::scoped_lock blocare(din.m, in.m);
din.sold -= suma;
in.sold += suma;
}
int main() {
Cont ana{{}, 1000};
Cont ion{{}, 1000};
std::thread t1([&] { for (int i = 0; i < 1000; ++i) transfera(ana, ion, 1); });
std::thread t2([&] { for (int i = 0; i < 500; ++i) transfera(ion, ana, 2); });
t1.join();
t2.join();
std::println("Ana: {}, Ion: {}, total: {}", ana.sold, ion.sold, ana.sold + ion.sold);
}
Rezultat
Ana: 1000, Ion: 1000, total: 2000
Greșeli frecvente
- Scrii
std::scoped_lock blocare();sau uiți să dai mutexurile. Nu se ocupă nimic. Scrie mereu mutexurile între paranteze.
Comenzi înrudite
std::lock_guard: Ocupă un mutex la creare și îl eliberează automat la ieșirea din bloc (RAII).std::mutex: Încuietoare pentru date comune: un singur fir de execuție o poate ține la un moment dat.std::unique_lock: Blocare de mutex flexibilă: poate fi eliberată și reluată, amânată, mutată; necesară pentru condition_variable.