Subject: [Boost-bugs] [Boost C++ Libraries] #4882: Win32 shared_mutex does not handle timeouts correctly
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2010-11-22 17:42:09
#4882: Win32 shared_mutex does not handle timeouts correctly
---------------------------------------------+------------------------------
Reporter: martin.jerabek@⦠| Owner: anthonyw
Type: Bugs | Status: new
Milestone: To Be Determined | Component: thread
Version: Boost 1.45.0 | Severity: Problem
Keywords: |
---------------------------------------------+------------------------------
I have identified two problems with the Win32 implementation of
boost::shared_mutex in case of timeouts:
Imagine the following scenario:
1. Three threads A, B, C compete for a shared_mutex in exclusive mode with
timeouts (timed_lock).
2. Thread A acquires the mutex. Thread B and C wait for it in
WaitForMultipleObjects, so exclusive_waiting is 2.
3. Thread A decides to release the mutex at the same time that thread B
returns from WaitForMultipleObjects with a timeout.
a. Thread A still sees exclusive_waiting == 2 because thread B has not
yet adjusted the mutex state.
It releases the mutex (exclusive = false), decrements
exclusive_waiting to 1 and releases the unlock_sem and exclusive_sem.
b. Thread B sees that no threads own the mutex for shared access
(shared_count == 0) and exclusive is false.
So it sets exclusive to true and now owns the mutex. Notice that it
does not do anything with exclusive_waiting, so it is still 1.
c. Thread C is woken up due to thread A releasing the semaphores.
It loops back to retry to get the mutex but this fails because the
mutex is already owned by thread B.
However, it still increments exclusive_waiting to 2.
After this process, exclusive_waiting is 2 although only one thread (C) is
waiting for the mutex.
If this is repeated often enough, timed_lock() will throw a lock_error
because exclusive_waiting reached 127 and wrapped to 0.
The attached program triggers this problem by simply starting 20 threads
which compete for the shared_mutex with a timeout in a loop.
On my dual-core 3GHz PC, the exception is thrown in less than a minute.
There is another similar failure mode:
1. Two threads A and B compete for a shared_mutex in exclusive mode with
timeouts (timed_lock).
2. Thread A owns the mutex and thread B waits for it in
WaitForMultipleObjects (exclusive_waiting == 1).
3. Again thread A releases the mutex at the same time that thread B
returns from WaitForMultipleObjects with a timeout.
a. Thread A again still sees exclusive_waiting == 1, so it releases the
mutex, decrements exclusive_waiting to zero,
and releases the semaphores.
b. Thread B again sees that the mutex is available and acquires it
without waiting for the semaphores because
it already returned from WaitForMultipleObjects with a timeout.
4. Thread A tries to acquire the mutex again in exclusive mode. It sees
that the mutex is locked, increments exclusive_waiting
to 1 and calls WaitForMultipleObjects to wait for thread B to release
the mutex.
5. However, the semaphores are still released from the time thread A
released the mutex before
but thread B never decremented them because it has already returned
from WaitForMultipleObjects with a timeout.
6. This means that thread A returns immediately from
WaitForMultipleObjects without a timeout.
It tries again to acquire the mutex which is still locked by thread B,
and it increments again exclusive_waiting
which is now 2.
This is again a bug because exclusive_waiting is 2 although only thread A
waits for the mutex.
To be honest, I do not know how to fix this bug. I think the basic problem
is that changing the mutex state and releasing the semaphores
is not a single atomic operation. A thread which returned from
WaitForMultipleObjects with a timeout
cannot know whether another thread decremented exclusive_waiting for it,
so it does not know whether or not it has to decrement
exclusive_waiting itself to restore the mutex state.
-- Ticket URL: <https://svn.boost.org/trac/boost/ticket/4882> Boost C++ Libraries <http://www.boost.org/> Boost provides free peer-reviewed portable C++ source libraries.
This archive was generated by hypermail 2.1.7 : 2017-02-16 18:50:04 UTC