mutex (C++)

std::lock (C++)

Locks the given Lockable objects lock1, lock2, …, lockn using a deadlock avoidance algorithm to avoid Deadlock.

void task_a () {
  // foo.lock(); bar.lock(); // replaced by:
  std::lock (foo,bar);
  std::cout << "task a\n";

Though generally, when we refer to locks in C++, we dont use the “naked” std::lock. The locks below employ RAII, which automatically lock and unlock a mutex. These are:

  • std::lock_guard
  • std::unique_lock
  • NEW std::scoped_lock


Mutex vs. Lock

Always prefer locks to mutexes, using a 1ock_guard

Motivation is here:

Locks take care of their resource following the RAII idiom. A lock automatically binds its mutex in the constructor and releases it in the destructor. This considerably reduces the risk of a deadlock because the runtime takes care of the mutex.


mutex m;
sharedVariable= getVar();
  • Easy to forget to unlock, easy to result in Deadlock


std::mutex m,
std::lock_guard<std::mutex> lockGuard(m);
sharedVariable= getVar();

Types of locks


The class lock_guard is a mutex wrapper that provides a convenient RAII-style mechanism for owning a mutex for the duration of a scoped block.

// lock_guard example
#include <iostream>       // std::cout
#include <thread>         // std::thread
#include <mutex>          // std::mutex, std::lock_guard
#include <stdexcept>      // std::logic_error
std::mutex mtx;
void print_even (int x) {
  if (x%2==0) std::cout << x << " is even\n";
  else throw (std::logic_error("not even"));
void print_thread_id (int id) {
  try {
    // using a local lock_guard to lock mtx guarantees unlocking on destruction / exception:
    std::lock_guard<std::mutex> lck (mtx);
  catch (std::logic_error&) {
    std::cout << "[exception caught]\n";
int main ()
  std::thread threads[10];
  // spawn 10 threads:
  for (int i=0; i<10; ++i)
    threads[i] = std::thread(print_thread_id,i+1);
  for (auto& th : threads) th.join();
  return 0;


std::unique_lock is mightier but more expansive than its small brother std::lock_guard.

unique_lock locks in exclusive mode.

#include <mutex>
#include <thread>
#include <iostream>
struct Box
    explicit Box(int num) : num_things{num} {}
    int num_things;
    std::mutex m;
void transfer(Box &from, Box &to, int num)
    // don't actually take the locks yet
    std::unique_lock lock1{from.m, std::defer_lock};
    std::unique_lock lock2{to.m, std::defer_lock};
    // lock both unique_locks without deadlock
    std::lock(lock1, lock2);
    from.num_things -= num;
    to.num_things += num;
    // 'from.m' and 'to.m' mutexes unlocked in 'unique_lock' dtors
int main()
    Box acc1{100};
    Box acc2{50};
    std::thread t1{transfer, std::ref(acc1), std::ref(acc2), 10};
    std::thread t2{transfer, std::ref(acc2), std::ref(acc1), 5};
    std::cout << "acc1: " << acc1.num_things << "\n"
                 "acc2: " << acc2.num_things << '\n';


shared_lock allows deferred locking, timed locking and transfer of lock ownership.

#include <shared_mutex>
#include <syncstream>
#include <iostream>
#include <thread>
#include <chrono>
std::shared_timed_mutex m;
int i = 10;
void read_shared_var(int id)
   // both the threads get access to the integer i
   std::shared_lock<std::shared_timed_mutex> slk(m);
   const int ii = i; // reads global i
   std::osyncstream(std::cout) << "#" << id << " read i as " << ii << "...\n";
   std::osyncstream(std::cout) << "#" << id << " woke up..." << std::endl;
int main()
   std::thread r1 {read_shared_var, 1};
   std::thread r2 {read_shared_var, 2};