Ce face std::mutex
Când mai multe fire modifică aceleași date, trebuie să se ia la rând. Un std::mutex („mutual exclusion”) garantează asta: m.lock() așteaptă până când mutexul este liber și îl ocupă, m.unlock() îl eliberează. Codul dintre ele (secțiunea critică) rulează pe un singur fir odată.
Nu apela lock/unlock manual: dacă între ele apare o excepție sau un return, mutexul rămâne blocat pentru totdeauna. Folosește std::lock_guard, std::unique_lock sau std::scoped_lock, care îl eliberează automat.
try_lock() încearcă să ocupe mutexul fără să aștepte și returnează false dacă este deja ocupat.
Ce returnează
try_lock() returnează true dacă a reușit. lock() și unlock() nu returnează nimic.
Exemple
Exemplul 1: Un contor modificat de 4 fire
Fără mutex, totalul ar ieși de multe ori mai mic de 40000 (și ar fi comportament nedefinit). Cu mutex, este mereu corect.
#include <mutex>
#include <print>
#include <thread>
#include <vector>
int main() {
int vizite = 0;
std::mutex m;
std::vector<std::thread> fire;
for (int i = 0; i < 4; ++i) {
fire.emplace_back([&] {
for (int j = 0; j < 10'000; ++j) {
std::lock_guard<std::mutex> blocare(m);
++vizite;
}
});
}
for (auto& t : fire) t.join();
std::println("Vizite: {}", vizite);
}
Rezultat
Vizite: 40000
Exemplul 2: try_lock
#include <mutex>
#include <print>
int main() {
std::mutex m;
m.lock();
std::println("a doua încercare reușește: {}", m.try_lock());
m.unlock();
if (m.try_lock()) {
std::println("mutex liber, l-am ocupat");
m.unlock();
}
}
Rezultat
a doua încercare reușește: false
mutex liber, l-am ocupat
Greșeli frecvente
- Uiți
unlock()pe o ramură (de exemplu unreturntimpuriu). Toate celelalte fire rămân blocate lalock(). Foloseștestd::lock_guard. - Apelezi
lock()de două ori pe același fir.std::mutexnu este recursiv: firul se blochează singur (comportament nedefinit). - Două fire ocupă două mutexuri în ordine inversă (A apoi B, respectiv B apoi A). Se pot bloca reciproc (deadlock); folosește
std::scoped_lockpentru amândouă.
Comenzi înrudite
std::lock_guard: Ocupă un mutex la creare și îl eliberează automat la ieșirea din bloc (RAII).std::unique_lock: Blocare de mutex flexibilă: poate fi eliberată și reluată, amânată, mutată; necesară pentru condition_variable.std::scoped_lock: Ocupă unul sau mai multe mutexuri deodată, fără risc de blocaj reciproc, și le eliberează automat.std::atomic: Variabilă care poate fi citită și modificată sigur de mai multe fire, fără mutex.std::thread: Pornește o funcție pe un fir de execuție separat, care rulează în paralel cu restul programului.