Skip to content

Mutex_locks

When multiple threads access shared data, we need synchronization. This chapter covers mutexes and locks.

#include <mutex>
int counter = 0;
std::mutex mtx;
void increment() {
mtx.lock();
counter++;
mtx.unlock();
}

Automatically locks and unlocks:

#include <mutex>
int counter = 0;
std::mutex mtx;
void increment() {
std::lock_guard<std::mutex> lock(mtx);
counter++; // Automatically unlocked when lock goes out of scope
}

More flexible than lock_guard:

std::unique_lock<std::mutex> lock(mtx);
lock.lock();
lock.unlock();
lock.try_lock();
// Can release lock early
lock.release();
// Can transfer ownership
std::unique_lock<std::mutex> lock2 = std::move(lock);
// Bad: Lock in different orders in different threads
void thread1() {
std::lock_guard<std::mutex> lock1(mutex1);
std::lock_guard<std::mutex> lock2(mutex2);
}
void thread2() {
std::lock_guard<std::mutex> lock2(mutex2);
std::lock_guard<std::mutex> lock1(mutex1); // Deadlock!
}
// Good: Lock in same order
void thread1() {
std::lock_guard<std::mutex> lock1(mutex1);
std::lock_guard<std::mutex> lock2(mutex2);
}
std::timed_mutex mtx;
if (mtx.try_lock_for(std::chrono::milliseconds(100))) {
// Successfully locked
mtx.unlock();
} else {
// Couldn't acquire lock
}
  • Use mutexes to protect shared data
  • Prefer lock_guard or unique_lock over raw lock/unlock
  • Avoid deadlock by consistent lock ordering
  • Use timed mutexes to avoid indefinite waiting