std::mutex (C++)

The mutex class is a synchronization primitive that can be used to protect shared data from being simultaneously accessed by multiple threads.

Mutex

Mutex as the name hints implies mutual exclusion. A mutex is used to guard shared data such as a linked-list, an array or any simple primitive type. A mutex allows only a single thread to access a resource.

First saw this with the Singleton pattern.

I am seeing this in NVIDIA codebase.

Resources

Locking functions:

  • lock: locks the mutex, blocks if the mutex is not available, see lock (C++)
  • try_lock: tries to lock the mutex, returns if the mutex is not available
  • unlock: unlocks the mutex

You need to include the <mutex> library to use this functionality

#include <mutex>          // std::mutex

An example

void print_block (int n, char c) {
  // critical section (exclusive access to std::cout signaled by locking mtx):
  mtx.lock();
  for (int i=0; i<n; ++i) { std::cout << c; }
  std::cout << '\n';
  mtx.unlock();
}
 
int main ()
{
  std::thread th1 (print_block,50,'*');
  std::thread th2 (print_block,50,'$');
 
  th1.join();
  th2.join();
 
  return 0;
}

Some more advanced mutexes in C++:

  • shared_time_mutex

shared_time_mutex

It’s shared_mutex + timed_mutex

shared_mutex: https://en.cppreference.com/w/cpp/thread/shared_mutex timed_mutex: https://en.cppreference.com/w/cpp/thread/timed_mutex

The shared_timed_mutex class is a synchronization primitive that can be used to protect shared data from being simultaneously accessed by multiple threads. In contrast to other mutex types which facilitate exclusive access, a shared_timed_mutex has two levels of access:

  • exclusive - only one thread can own the mutex.
  • shared - several threads can share ownership of the same mutex.

Shared mutexes are usually used in situations when multiple readers can access the same resource at the same time without causing data races, but only one writer can do so.

https://en.cppreference.com/w/cpp/thread/shared_timed_mutex

Also look at this https://stackoverflow.com/questions/40207171/why-shared-timed-mutex-is-defined-in-c14-but-shared-mutex-in-c17

https://www.justsoftwaresolutions.co.uk/threading/new-concurrency-features-in-c++14.html

std::lock_guard

https://cplusplus.com/reference/mutex/lock_guard/

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);
    print_even(id);
  }
  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;
}