Search code examples
c++thread-safetylockingunique-lock

Is it safe to wait/notify on unique_lock mutexes when same mutexes are used with lock_guard on somewhere else?


I was using following kind of wait/signal way to let threads inform each other.

std::condition_variable condBiz;
std::mutex mutexBar;
..
void Foo::wait()
{
    std::unique_lock<std::mutex> waitPoint(mutexBar);
    if (waitPoint.owns_lock())
    {
        condBiz.wait(waitPoint);
    }
}
void Foo::signal()
{
    std::unique_lock<std::mutex> waitPoint(mutexBar);
    condBiz.notify_all();
}
void Foo::safeSection(std::function<void(void)> & f)
{
   std::unique_lock<std::mutex> waitPoint(mutexBar); 
   f();
}

Then converted lock/unlock mechanism from unique_lock to lock_guard because I'm not returning unique_lock to use somewhere else(other than wait/signal) and lock_guard is said to have less overhead:

void Foo::safeSection(std::function<void(void)> & f)
{
   std::lock_guard<std::mutex> waitPoint(mutexBar);  // same mutex object
   f();
}

and it works.

Does this work for all platforms or just looks like working for current platform? Can unique_lock and lock_guard work with each other using same mutex object?


Solution

  • Both std::unique_lock and std::lock_guard lock the associated mutex in the constructor and unlock it in the destructor.

    std::unique_lock:

    Member functions

    (constructor) constructs a unique_lock, optionally locking the supplied mutex
    (destructor) unlocks the associated mutex, if owned

    and the same for std::lock_guard:

    Member functions

    (constructor) constructs a lock_guard, optionally locking the given mutex
    (destructor) destructs the lock_guard object, unlocks the underlying mutex

    Since both behave the same, when used as a RAII style wrapper, I see no obstacle to use them together, even with the same mutex.