Boost logo

Boost Users :

Subject: Re: [Boost-users] interprocess_condition::wait(scoped_lock<interprocess_upgradable_lock> &) missing
From: Howard Hinnant (howard.hinnant_at_[hidden])
Date: 2011-02-03 21:05:07


On Feb 3, 2011, at 8:14 PM, John Ky wrote:

> It would be nice to have a condition_variable_any that supports any kind of lock.
>
> It's probably okay if there were a condition_variable_* class for each lock type as well. Or did you mean something like condition_variable_any<Mutex>?

A condition_variable_any<Mutex> is counter-productive. What you really need is:

class condition_variable_any
{
public:
    condition_variable_any();
    ~condition_variable_any();

    condition_variable_any(const condition_variable_any&) = delete;
    condition_variable_any& operator=(const condition_variable_any&) = delete;

    void notify_one();
    void notify_all();

    template <class Lock>
        void wait(Lock& lock);
    template <class Lock, class Predicate>
        void wait(Lock& lock, Predicate pred);

    template <class Lock, class Clock, class Duration>
        cv_status
        wait_until(Lock& lock,
                   const chrono::time_point<Clock, Duration>& abs_time);

    template <class Lock, class Clock, class Duration, class Predicate>
        bool
        wait_until(Lock& lock,
                   const chrono::time_point<Clock, Duration>& abs_time,
                   Predicate pred);

    template <class Lock, class Rep, class Period>
        cv_status
        wait_for(Lock& lock,
                 const chrono::duration<Rep, Period>& rel_time);

    template <class Lock, class Rep, class Period, class Predicate>
        bool
        wait_for(Lock& lock,
                 const chrono::duration<Rep, Period>& rel_time,
                 Predicate pred);
};

I.e. only the wait functions are templated on the lock. This allows one cv to be waited on by two different kinds of locks at the same time. For example one thread could wait on the thread with a shared_lock while another thread waited on the same cv with a unique_lock (but using the same underlying shared_mutex):

shared_mutex mut;
condition_variable_any cv;

void wait_in_shared_ownership_mode()
{
    shared_lock<shared_mutex> shared_lk(mut);
    // mut is now shared-locked
    // ...
    while (not_ready_for_shared_to_proceed())
        cv.wait(shared_lk); // shared-lock released while waiting
    // mut is now shared-locked
    // ...
} // mut is now unlocked

void wait_in_unique_ownership_mode()
{
    unique_lock<shared_mutex> lk(mut);
    // mut is now unique-locked
    // ...
    while (not_ready_for_unique_to_proceed())
        cv.wait(lk); // unique-lock released while waiting
    // mut is now unique-locked
    // ...
} // mut is now unlocked

A third thread could change either the not_ready_for_shared_to_proceed predicate, the not_ready_for_unique_to_proceed predicate, or both, and then cv.notify_all(). This is very powerful stuff when you need it (most of the time condition_variable and mutex are all you need).

In this set condition_variable_any and unique_lock are in C++0x. I hope to propose shared_lock and shared_mutex for tr2 and ultimately c++1x. Field experience here (good or bad) would help. Here is a tutorial and implementation of the shared and upgrade mutexes and locks:

http://home.roadrunner.com/~hinnant/mutexes/locking.html

Here is an implementation of condition_variable_any:

http://llvm.org/svn/llvm-project/libcxx/trunk/include/condition_variable

-Howard


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net