Boost logo

Threads-Devel :

Subject: Re: [Threads-devel] Verifying boost::condition_variable_anyplays nicely with boost::recursive_mutex
From: Gregory Peele ARA/CFD (gpeele_at_[hidden])
Date: 2009-01-12 17:05:07


It's good to know my tests aren't flawed and this was in fact
intentional behavior. I'm curious though - what is the rationale for
not saving and restoring the lock state as you described for recursive
mutexes? Only one thread can hold locks on the mutex at a time, and the
user presumably intended for condition_variable_any::wait to allow other
threads to lock the mutex and update shared state that the condition is
waiting for. Certainly the user doesn't call into that method intending
to create a deadlock, and other language implementations agree that
saving / restoring the lock state is the proper behavior. I don't see
how this can break any recursive_mutex invariants. The following states
are possible:

 * Thread A has >= 1 active locks on mutex, all other threads contending
for mutex locks are excluded
 * Thread A is asleep or going to sleep in
condition_variable_any::wait(), fully releases mutex, all other threads
contending for mutex can acquire locks per normal recursive mutex rules
 * Thread A woke up (either by interruption or notify), is in
condition_variable_any::wait(), and is attempting to reacquire a lock on
the mutex, but is excluded by Thread B that currently holds >= 1 locks
 * Thread A woke up (either by interruption or notify), is in
condition_variable_any::wait(), acquired a mutex lock (after which all
other threads are excluded from acquiring any locks), restores lock
count state, then returns from wait()

>From the caller's perspective, the proper number of recursive locks
would be held entering wait(), and the proper number of recursive locks
would be held leaving wait() whether by normal return or exception
(including interruption.) I'm not clear where this could go wrong.
Other language implementations have proven that this works as intended.
I've relied on this behavior in Java since I do not feel it is
reasonable to expect all users of my classes (particularly those who
subclass them) to know which methods hold a lock on the mutex and have
to work around it. If this behavior is not guaranteed, then there is no
real reason to use recursive_mutex in my opinion.

I can't make heads or tails of the win32 backend for recursive_mutex or
condition_variable_any though, so maybe the reasons why this behavior
was chosen have to do with platform-specific details I'm not aware of.

Greg Peele,
Applied Research Associates, Inc.

-----Original Message-----
From: threads-devel-bounces_at_[hidden]
[mailto:threads-devel-bounces_at_[hidden]] On Behalf Of Anthony
Williams
Sent: Monday, January 12, 2009 4:22 PM
To: threads-devel_at_[hidden]
Subject: Re: [Threads-devel] Verifying
boost::condition_variable_anyplays nicely with boost::recursive_mutex

At Mon 12 Jan 2009 21:01:16 UTC, Gregory Peele ARA/CFD <gpeele_at_[hidden]>
wrote:

> I've recently been tasked with writing a Java-style cross-platform
> asynchronous task execution service in C++ on top of Boost Threads
1.37.
> After implementing this service, my unit tests discovered some
> unexpected behavior (well, unexpected to me anyways) with the way that
> boost::condition_variable_any, boost::recursive_mutex, and
> boost::unique_lock interact. I wanted to find out if this behavior is
> intentional or if it should be considered a bug.
>
> Basically, the problem occurs when the same thread has multiple
> unique_lock objects associated with the same recursive_mutex, and then
> calls condition_variable_any::wait. It appears that the condition
> variable only releases one of the recursive locks, and the mutex is
> still considered locked by the calling thread.

That's as designed. condition_variable_any::wait() calls unlock on the
supplied mutex/lock exactly once. If you use a recursive mutex then
you need to ensure that the calling thread only owns a single lock, or
use a lock wrapper that will save and restore the lock count.

If the wait released all locks held on that mutex this may lead to
bugs with the mutex being implicitly unlocked with broken invariants.

Anthony

-- 
Anthony Williams
Author of C++ Concurrency in Action | http://www.manning.com/williams
Custom Software Development | http://www.justsoftwaresolutions.co.uk
Just Software Solutions Ltd, Registered in England, Company Number
5478976.
Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK
_______________________________________________
threads-devel mailing list
threads-devel_at_[hidden]
http://lists.boost.org/mailman/listinfo.cgi/threads-devel

Threads-Devel list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk