Skip to main content
AI Assist is now on Stack Overflow. Start a chat to get instant answers from across the network. Sign up to save and share your chats.
deleted 21 characters in body
Source Link
Solomon Slow
  • 27.6k
  • 5
  • 39
  • 61
std::mutex m; { ... while (...) { do_work_outside_critical_section(); m.lock();  // explicitly put a "lock" back on the mutex. do_work_inside_critical_section(); m.unlock();  // explicitly remove the "lock." } } 
std::mutex m; { ... while (...) { do_work_outside_critical_section(); std::unique_lock<std::mutex> lk(m);  // constructor puts a "lock" on the mutex. do_work_inside_critical_section(); }  // destructor implicitly removes the "lock." } 
std::mutex m; { ... std::unique_lock<std::mutex> lk(m);  // constructor puts a "lock" on the mutex. while (...) { lk.unlock();  // explicitly remove the "lock" from the mutex. do_work_outside_critical_section(); lk.lock();  // explicitly put a "lock" back on the mutex. do_work_inside_critical_section(); } }  // destructor implicitly removes the "lock." 
std::mutex m; { ... while (...) { do_work_outside_critical_section(); m.lock();  // explicitly put a "lock" back on the mutex. do_work_inside_critical_section(); m.unlock();  // explicitly remove the "lock." } } 
std::mutex m; { ... while (...) { do_work_outside_critical_section(); std::unique_lock<std::mutex> lk(m);  // constructor puts a "lock" on the mutex. do_work_inside_critical_section(); }  // destructor implicitly removes the "lock." } 
std::mutex m; { ... std::unique_lock<std::mutex> lk(m);  // constructor puts a "lock" on the mutex. while (...) { lk.unlock();  // explicitly remove the "lock" from the mutex. do_work_outside_critical_section(); lk.lock();  // explicitly put a "lock" back on the mutex. do_work_inside_critical_section(); } }  // destructor implicitly removes the "lock." 
std::mutex m; { ... while (...) { do_work_outside_critical_section(); m.lock(); // explicitly put a "lock" on the mutex. do_work_inside_critical_section(); m.unlock(); // explicitly remove the "lock." } } 
std::mutex m; { ... while (...) { do_work_outside_critical_section(); std::unique_lock<std::mutex> lk(m); // constructor puts a "lock" on the mutex. do_work_inside_critical_section(); } // destructor implicitly removes the "lock." } 
std::mutex m; { ... std::unique_lock<std::mutex> lk(m); // constructor puts a "lock" on the mutex. while (...) { lk.unlock(); // explicitly remove the "lock" from the mutex. do_work_outside_critical_section(); lk.lock(); // explicitly put a "lock" back on the mutex. do_work_inside_critical_section(); } } // destructor implicitly removes the "lock." 
Source Link
Solomon Slow
  • 27.6k
  • 5
  • 39
  • 61

This is not an answer. It's just an illustration. I turned your one example into three different examples that all achieve the same result. I hope it may help you to better understand what unique_lock does.

The first way doesn't use unique_lock at all. It only uses the mutex. This is the old-school way—the way we used to do things before RAII was discovered.

std::mutex m; { ... while (...) { do_work_outside_critical_section(); m.lock(); // explicitly put a "lock" back on the mutex. do_work_inside_critical_section(); m.unlock(); // explicitly remove the "lock." } } 

The old-school way is risky because if do_work_inside_critical_section() throws an exception, it will leave the mutex in a locked state, and any thread that tries to lock it again probably will hang forever.


The second way uses unique_lock, which is an embodiment of RAII.

The RAII pattern ensures that there's no way out of this code block that leaves a lock on mutex m. The unique_lock destructor always will be called, no matter what, and the destructor removes the lock.

std::mutex m; { ... while (...) { do_work_outside_critical_section(); std::unique_lock<std::mutex> lk(m); // constructor puts a "lock" on the mutex. do_work_inside_critical_section(); } // destructor implicitly removes the "lock." } 

Notice that in this version, a unique_lock is constructed and destructed every time around the loop. That might sound costly, but it really isn't. unique_lock is meant to be used in this way.


The last way is what you did in your example. It only creates and destroys the unique_lock one time, but then it repeatedly locks and unlocks it within the loop. This works, but it's more code lines than the version above, which makes it a little bit harder to read and understand.

std::mutex m; { ... std::unique_lock<std::mutex> lk(m); // constructor puts a "lock" on the mutex. while (...) { lk.unlock(); // explicitly remove the "lock" from the mutex. do_work_outside_critical_section(); lk.lock(); // explicitly put a "lock" back on the mutex. do_work_inside_critical_section(); } } // destructor implicitly removes the "lock." 
Post Made Community Wiki by Solomon Slow