Home > Software design >  unique_lock same mutex in different thread
unique_lock same mutex in different thread

Time:09-13

i am looking at this piece of code:

#include <chrono>
#include <iostream>
#include <map>
#include <mutex>
#include <shared_mutex>
#include <string>
#include <thread>

bool flag;
std::mutex m;

void wait_for_flag() {
  // std::cout << &m << std::endl;
  // return;
  std::unique_lock<std::mutex> lk(m);
  while (!flag) {
    lk.unlock();
    std::cout << "unlocked....." << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    std::cout << "sleeping....." << std::endl;
    lk.lock();
    std::cout << "locked by " << std::this_thread::get_id() << "....."
              << std::endl;
  }
}

int main(int argc, char const *argv[]) {
  std::thread t(wait_for_flag);
  std::thread t2(wait_for_flag);
  std::thread t3(wait_for_flag);
  std::thread t4(wait_for_flag);
  std::thread t5(wait_for_flag);

  t.join();
  t2.join();
  t3.join();
  t4.join();
  t5.join();

  return 0;
}

I am new to this, and I thought mutex can only be acquired by one thread. I got two questions:

  1. why there is no deadlock among those threads, e.g. if thread A runs lk.unlock(), then thread B runs lk.lock() and then thread A runs lk.lock().
  2. what does it mean we define a new unique_lock in every thread associating to the same mutex lock (which is called m in here)

Thanks

CodePudding user response:

Because right after acquiring a lock on the mutex each thread calls lk.unlock(); and now other thread can acquire a lock on the mutex. Only if a thread tries to lock an already locked mutex (by a different thread) it has to wait for the mutex to be free. As any thread in your code eventually calls lk.unlock(); there is always a chance for a different thread to get a lock on the mutex and there is no deadlock.

A deadlock would occur for example if you have two mutexes and two threads try to lock them in different order:

  // thread A
  std::unique_lock<std::mutex> lk1(mutex1);
  std::unique_lock<std::mutex> lk2(mutex2);    // X

  // thread B
  std::unique_lock<std::mutex> lk2(mutex2);
  std::unique_lock<std::mutex> lk1(mutex1);    // X

Here it can happen that thread A locks mutex1, thread B locks mutex2 and then both wait in X for the other thread to release the other mutex, but this will never happen. Its a deadlock.

2.

A lock is merely a slim RAII type. Its only purpose is to call lock on the mutex when created and unlock when destroyed. You can write the same code without the lock, by manually locking / unlocking the mutex, but when there is an exception while a mutex is locked it will never be unlocked.

  • Related