boost scoped_lock vs plain lock/unlock

Max picture Max · Mar 2, 2013 · Viewed 24.5k times · Source

I'm going to use boost::mutex from boost/thread/mutex.hpp. There are several ways to lock/unlock mutex: with scoped_lock, unique_lock, lock_guard, mutex's member functions ::lock() and ::unlock() and nonmember functions lock() and unlock().

I noticed, that boost::scoped_mutex is one of the most popular ways of using mutex. Why is it preferable to member functions ::lock() and ::unlock()?

Particularly, why should I use

{
  boost::scoped_lock lock(mutex)
  // ...
  // read/output sharing memory.
  // ...
}

rather than

mutex.lock()
// ...
// read/output sharing memory.
// ...
mutex.unlock()

is scoped_lock better just because of some style-coding point of view or is ::lock()/::unlock() not "thread safe enough"?

Answer

Andy Prowl picture Andy Prowl · Mar 2, 2013

Why is it preferable to member functions ::lock() and ::unlock()?

For the same reason why the RAII idiom became popular in general (this is just one of its countless instances): because you can be sure you don' leave the current scope without unlocking the mutex.

Notice, that this is not just about forgetting to call unlock(): an exception may occur while your mutex is locked, and your call to unlock() may never be reached, even though you do not have any return statement between your call to lock() and your call to unlock().

m.lock() // m is a mutex
// ...
foo(); // If this throws, your mutex won't get unlocked
// ...
m.unlock()

In this case, the destructor of your scoped_lock guard will be invoked during stack unwinding, making sure the associated mutex always gets released.

{
    boost::scoped_lock lock(m); // m is a mutex
    // ...
    foo(); // If this throws, your RAII wrapper will unlock the mutex
    // ...
}

Moreover, in many situations this will improve your code's readability, in that you won't have to add a call to unlock() before every return statement.