Boost logo

Boost :

From: Howard Hinnant (hinnant_at_[hidden])
Date: 2007-08-22 11:23:49


On Aug 21, 2007, at 7:34 PM, Yuval Ronen wrote:

> All this complexity is simply unnecessary, IMO. You can drop the
> lock/try_lock/unlock functions from the locks, keep them for mutexes,
> and declare that std::lock/scoped_lock/unique_lock work only for
> mutexes. You can then drop defer_lock also, and everything is much
> simpler...

Consider a use case where the mutex, but not the lock has been
encapsulated away, and you want to unlock the lock prior to its
destruction:

typedef std::mutex Mutex;

Mutex&
get_mutex()
{
     static Mutex mut;
     return mut;
}

typedef std::unique_lock<Mutex> Lock;

Lock
get_lock()
{
     return Lock(get_mutex());
}

typedef std::condition<Mutex> Condition;

Condition&
get_condition()
{
     static Condition cv(get_mutex());
     return cv;
}

void foo()
{
     Lock lk = get_lock();
     change_data();
     if (some_flag)
     {
         lk.unlock(); // <--------- here
         get_condition().notify_all();
     }
}

The author of foo() wants to unlock the lock prior to calling
notify_all on the cv as an optimization. This means that waking
threads are more likely to be able to obtain the lock on the mutex
since foo() is no longer holding it. It isn't desirable to use a
mutex directly here. change_data() could throw an exception, and we
do not want the lock ownership of the mutex leaked in that case. The
author does not want to unlock lk prior to the if statement because
"some_flag" is also part of the data protected by the mutex. It must
be read under its protection. We could do something like:

void foo()
{
     bool local_some_flag;
     {
     Lock lk = get_lock();
     change_data();
     local_some_flag = some_flag;
     }
     if (local_some_flag)
         get_condition().notify_all();
}

But this does not seem like an improvement to me. It is not simpler.
It is not easier to use. It is not faster. It is not smaller. It is
simply avoiding the use of an explicit unlock on lk. <shrug>

My goal is to enable programmers to use these tools in ways that
*they* choose. Not in ways that I demand. The design is meant to
encourage safety, but not be a nanny. To enable thinking about
synchronization at a higher level than pthread_mutex_t and
pthread_cond_t. And to never force the programmer to pay performance
for a feature he doesn't need or want.

Question 10 shows a motivating use case for defer_lock that does not
involve the member lock/unlock functions on locks.

-Howard


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk