boost::thread_v2::upgrade_mutex corrupted when thread is interrupted
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 35/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Stale
- Tech stack
- cpp
- Domain
- operating-systems
Research direction
Start with the provided reproducer, defining BOOST_THREAD_V2_SHARED_MUTEX, and trace the boost::shared_mutex/upgrade_mutex locking path used by unique_lock_t while t2 waits for the reader. Compare the interrupted path with the normal lock path; done means the reader can finish and mut.try_lock() succeeds after t2 is interrupted.
Written by the indexing model from the issue text.
Description
When a thread tries to obtain an exclusive lock on a boost::thread_v2::upgrade_mutex and is interrupted while waiting for all readers to finish, the mutex is left in a locked state. In turn, no other thread is able to lock the mutex again.
The "owning" thread is unaware of this, as the function lock() returned with an exception.
While interruptions are one way of leading to this problem, it might actually be a more general issue of exception safety.
While this mutex implementation seems to be not used much, it is the workaround for the writer starvation issue of the default mutex implementation on Linux.
It seems like the default mutex implementation disables interruptions while trying to aquire the lock. I don't know if that is enough or if other exceptions might occur as well.
Example code how to reproduce:
#define BOOST_THREAD_V2_SHARED_MUTEX
#include <boost/thread.hpp>
using mutex_t = boost::shared_mutex;
using shared_lock_t = boost::shared_lock<boost::shared_mutex>;
using unique_lock_t = boost::unique_lock<boost::shared_mutex>;
int main(int, char**) {
mutex_t mut;
boost::barrier readerReady(2), readerDone(2);
auto t1 = boost::thread([&]() {
shared_lock_t guard(mut);
readerReady.wait();
readerDone.wait();
});
readerReady.wait();
auto t2 = boost::thread([&]() {
unique_lock_t guard(mut);
});
boost::this_thread::sleep_for(boost::chrono::seconds(2));
t2.interrupt();
t2.join();
readerDone.wait();
t1.join();
BOOST_ASSERT(mut.try_lock());
return 0;
}
Please note that the example does not terminate when BOOST_THREAD_V2_SHARED_MUTEX is not defined. It then hangs in t2.join(), as t2 has disabled interruptions when acquiring a lock.
- Dominant language
- C++
- Stars
- 213
- Forks
- 171
- PR merge metrics
- No merged PRs in 30d
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from boostorg/thread
-
Difficulty 1/5 Under an hour Newbie friendliness 65/100
-
Difficulty 3/5 1-2 days Newbie friendliness 64/100
-
Difficulty 3/5 1-2 days Newbie friendliness 42/100
-
Difficulty 4/5 3-5 days Newbie friendliness 45/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 58/100
Similar issues
-
Difficulty 1/5 Under an hour Newbie friendliness 90/100
AXERA-TECH/ax-llm#77 ·
-
Difficulty 1/5 Under an hour Newbie friendliness 90/100
games-on-whales/wolf#509 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
-
bug-unconfirmed
Difficulty 2/5 1-3 hours Newbie friendliness 76/100