Mutex Class

  • The C++ Standard Library provides an std::mutex class
    • Defined in <mutex>
  • A mutex object must be visible in all task functions which uses it
  • It must also be defined outside the task functions
    • Global/static variable with global function
    • Class data member with member task function
    • Variable captured by reference with lambda expressions

std::mutex Interface

  • Three main member functions:

  • lock()

    • Tries to lock the mutex
    • If not successful, waits until it locks the mutex
  • try_lock()

    • Tries to lock the mutex
    • Returns immediately if not successful
  • unlock()

    • Releases the lock on the mutex

#include <iostream>
#include <mutex>
#include <string>
#include <thread>

std::mutex task_mutex;

void task(const std::string &str) {
  for (int i = 0; i < 5; ++i) {
    // Lock mutex before critical section
    task_mutex.lock();

    std::cout << str[0] << str[1] << str[2] << std::endl;

    // Unlock mutex after critical section
    task_mutex.unlock();
  }
}

int main() {
  std::thread thr1(task, "abc");
  std::thread thr2(task, "def");
  std::thread thr3(task, "xyz");

  thr1.join();
  thr2.join();
  thr3.join();
}

  • The output is no longer scrambled up
  • The accesses to the critical section are synchronized
  • This prevents the threads from interfering with each other

std::mutex::try_lock()

  • try_lock() returns immediately

    • Returns true if it locked the mutex
    • Returns false if it could not lock the mutex
  • Usually called in a loop


#include <iostream>
#include <mutex>
#include <thread>

using namespace std::literals;

std::mutex the_mutex;

void task1() {
  std::cout << "Task1 trying to lock the mutex\n";
  the_mutex.lock();
  std::cout << "Task1 has locked the mutex\n";
  std::this_thread::sleep_for(500ms);
  std::cout << "Task1 unlocking the mutex\n";
  the_mutex.unlock();
}

void task2() {
  std::this_thread::sleep_for(100ms);
  std::cout << "Task2 trying to lock the mutex\n";
  while (!the_mutex.try_lock()) {
    std::cout << "Task2 could not lock the mutex\n";
    std::this_thread::sleep_for(100ms);
  }
  std::cout << "Task2 has locked the mutex\n";
  the_mutex.unlock();
}

int main() {
  std::thread thr1(task1);
  std::thread thr2(task2);

  thr1.join();
  thr2.join();
}