Hello,
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. All of my other methods in the
unit test that call notify_one or notify_all require acquiring a lock on the
recursive_mutex to modify non-trivial shared state checked by the condition, so
they deadlock. Refactoring the code so that the thread never acquires
more than one lock on the mutex in any call sequence fixes the deadlock, but I
feel that requiring my code maintainers and API users to honor this restriction
is excessively unfriendly.
This behavior is unexpected to me because the Java and C#
implementations of conditions and recursive mutexes (including the implicit
ones in Object synchronization) do not have this deadlock – the condition
variable wait properly releases all locks that the thread holds rather than
just one, and when the thread waits up and reacquires the lock, the recursive
count is properly restored. Is this a bug or is this intentional? If
it is intentional, then I most likely have misunderstood the appropriate use
case for unique_lock or how condition variables work in Boost (the different
use cases for the locks are not especially clear in the documentation) and
would like to know how to accomplish what my code tried to do.
Greg Peele
Applied Research Associates, Inc.