inline void interprocess_condition::do_wait(interprocess_upgradable_mutex &mut){scoped_unlock<interprocess_upgradable_mutex> unlock(mut);interprocess_mutex &internal_mutex = mut.m_mut;scoped_lock<interprocess_mutex> internal_lock(internal_mutex);this->wait(internal_lock);}inline bool interprocess_condition::do_timed_wait(const syssrv_boost::posix_time::ptime &abs_time, interprocess_upgradable_mutex &mut){scoped_unlock<interprocess_upgradable_mutex> unlock(mut);interprocess_mutex &internal_mutex = mut.m_mut;scoped_lock<interprocess_mutex> internal_lock(internal_mutex);return this->timed_wait(internal_lock, abs_time);}
Hi boost users,I've discovered that the following doesn't compile.using namespace boost::interprocess;interprocess_upgradable_mutex mutex;interprocess_condition cv;boost::posix_time::ptime deadline;{scoped_lock<interprocess_upgradable_mutex> lock(mutex);sharable_lock<interprocess_upgradable_mutex> lock2(mutex);cv.wait(lock); // doesn't compilecv.timed_wait(lock, deadline); // doesn't compile.}It is failing because boost doesn't define the following methods:
void interprocess_condition::do_wait(interprocess_upgradable_mutex &mut);bool interprocess_condition::do_timed_wait(const boost::posix_time::ptime &abs_time, interprocess_upgradable_mutex &mut);
I was thinking of making a basic implementation like so:Define a scoped_unlock class, which behaves just like scoped_lock except the constructor unlocks and the destructor locks.Then define the following:
inline void interprocess_condition::do_wait(interprocess_upgradable_mutex &mut){scoped_unlock<interprocess_upgradable_mutex> unlock(mut);interprocess_mutex &internal_mutex = mut.m_mut;scoped_lock<interprocess_mutex> internal_lock(internal_mutex);this->wait(internal_lock);}inline bool interprocess_condition::do_timed_wait
(const boost::posix_time::ptime &abs_time, interprocess_upgradable_mutex &mut)
{scoped_unlock<interprocess_upgradable_mutex> unlock(mut);interprocess_mutex &internal_mutex = mut.m_mut;scoped_lock<interprocess_mutex> internal_lock(internal_mutex);return this->timed_wait(internal_lock, abs_time);}
Condition variables are only compatible with interprocess_mutex. I think
they have no sense with other types of locks, because a mutex and a
condition variable should know each other. In POSIX, condition variables
are not compatible even with POSIX recursive locks, not to mention user
defined locking primitives.
Best,
Ion
_______________________________________________
Boost-users mailing list
Boost...@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users
But upgradable mutex could be implemented without using
interprocess_mutex, that's an implementation detail. I don't see the
need to use an upgradable lock. POSIX does not support condition
variables with read-write locks (although I think Windows Vista does) so
Interprocess does not offer any support for this.
I think you are trying to support a condition variable that could accept
any kind of lock. That sounds like condition_variable_any, a class that
is not implemented in Interprocess yet. The interface of
condition_variable might suggest that it supports any kind of lock, but
it is not true. I think I should state clearly this requirement in the
documentation and the code and maybe try to support
condition_variable_any in the future.
Best,
> 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
> 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
Thanks Howard! Just two comments:
a) Windows Vista condition variables natively supports Slim
Reader/Writer Locks
(http://msdn.microsoft.com/en-us/library/ms686304%28v=VS.85%29.aspx),
the implementation could take advantage of this if shared_mutex is based
on this primitive.
b) Is there any reason to store shared_ptr<mutex> instead of a mutex?
Best,
Ion
> El 04/02/2011 3:05, Howard Hinnant escribió:
>
>> 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
>
> Thanks Howard! Just two comments:
>
> a) Windows Vista condition variables natively supports Slim Reader/Writer Locks (http://msdn.microsoft.com/en-us/library/ms686304%28v=VS.85%29.aspx), the implementation could take advantage of this if shared_mutex is based on this primitive.
<nod> Agreed.
>
> b) Is there any reason to store shared_ptr<mutex> instead of a mutex?
Yes. I missed this subtlety for years. I think it was Peter Dimov who pointed it out to me:
Thread A notfies the condition_variable_any, which thread B is waiting on. Then thread A destructs the condition_variable_any before thread B wakes and returns from the wait. This is supposed to work. The POSIX condition variable also works this way. The shared_ptr is used to share ownership of the mutex between the condition_variable_any, and the thread running the wait function. If the condition_variable_any destructs while the wait is running, the mutex stays alive long for the wait function to lock and unlock it, and then destructs when the wait returns.
-Howard