Boost logo

Boost :

From: Howard Hinnant (hinnant_at_[hidden])
Date: 2007-11-15 12:15:39


On Nov 15, 2007, at 10:24 AM, Alexander Terekhov wrote:

>
> Howard Hinnant wrote:
>>
>> On Nov 15, 2007, at 7:02 AM, Alexander Terekhov wrote:
>>
>>>> http://svn.boost.org/svn/boost/trunk/boost/thread/pthread/condition_variable.hpp
>>>
>>> That condition_variable_any wrapper doesn't ensure same destruction
>>> safety of condition varaible as POSIX pthread_cond_t. That's not
>>> good.
>>
>> Thanks for this observation Alexander. Do you have a recommendation
>> for fixing it? The best I'm coming up with at the moment is to
>> keep a
>> count of waiters as member data and have ~condition_variable_any()
>> wait until the count drops to zero.
>
> Or simply use shared_ptr<pthread_mutex_t> for internal_mutex. Peter
> will like that. :-)

:-)

Thanks Alexander. I've been debugging this beast for years now.
Maybe, just maybe, it's debugged now. :-)

struct __lock_external
{
     template <class _Lock>
     void operator()(_Lock* __m) {__m->lock();}
};

class condition_variable_any
{
     condition_variable cv_;
     shared_ptr<mutex> mut_;
public:

     condition_variable_any() : mut_(new mutex) {}
     // ~condition_variable_any() = default;

     // 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>
         bool timed_wait(Lock& lock, const system_time& abs_time);
     template <class Lock, class Predicate>
         bool timed_wait(Lock& lock, const system_time& abs_time,
Predicate pred);
     template <class Lock, class Duration, class Predicate>
         bool timed_wait(Lock& lock, const Duration& rel_time,
Predicate pred);
};

inline
void
condition_variable_any::notify_one()
{
     lock_guard<mutex> _(*mut_);
     cv_.notify_one();
}

inline
void
condition_variable_any::notify_all()
{
     lock_guard<mutex> _(*mut_);
     cv_.notify_all();
}

template <class Lock>
void
condition_variable_any::wait(Lock& lock)
{
     shared_ptr<mutex> mut = mut_;
     unique_lock<mutex> lk(*mut);
     lock.unlock();
     unique_ptr<Lock, __lock_external> external_guard(&lock);
     lock_guard<unique_lock<mutex>> internal_guard(lk, adopt_lock);
     cv_.wait(lk);
} // mut_.unlock(), lock.lock()

template <class Lock, class Predicate>
inline
void
condition_variable_any::wait(Lock& lock, Predicate pred)
{
     while (!pred())
         wait(lock);
}

template <class Lock>
bool
condition_variable_any::timed_wait(Lock& lock, const system_time&
abs_time)
{
     shared_ptr<mutex> mut = mut_;
     unique_lock<mutex> lk(*mut);
     lock.unlock();
     unique_ptr<Lock, __lock_external> external_guard(&lock);
     lock_guard<unique_lock<mutex>> internal_guard(lk, adopt_lock);
     return cv_.timed_wait(lk, abs_time);
} // mut_.unlock(), lock.lock()

template <class Lock, class Predicate>
inline
bool
condition_variable_any::timed_wait(Lock& lock, const system_time&
abs_time, Predicate pred)
{
     while (!pred())
         if (!timed_wait(lock, abs_time))
             return pred();
     return true;
}

template <class Lock, class Duration, class Predicate>
inline
bool
condition_variable_any::timed_wait(Lock& lock, const Duration&
rel_time, Predicate pred)
{
     return timed_wait(lock, get_system_time() + rel_time,
std::move(pred));
}

> BTW, condition_variable_any's (timed_}wait() above doesn't seem to
> m.lock() in the case of threads cancel (interruption). That doesn't
> match POSIX (and condition_variable thin wrapper) behavior.

<nod>

-Howard


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