Subject: [Boost-bugs] [Boost C++ Libraries] #5516: Upgrade lock is not acquired when previous upgrade lock releases if another read lock is present
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2011-05-04 08:55:07
#5516: Upgrade lock is not acquired when previous upgrade lock releases if another
read lock is present
-----------------------------------+----------------------------------------
Reporter: fred@⦠| Owner: anthonyw
Type: Bugs | Status: new
Milestone: To Be Determined | Component: threads
Version: Boost 1.42.0 | Severity: Problem
Keywords: |
-----------------------------------+----------------------------------------
Thread 1 acquires a read lock on a shared mutex[[BR]]
Thread 2 acquires an upgrade lock on the shared mutex[[BR]]
Thread 3 tries to acquire an upgrade lock on the shared mutex, waits for
it[[BR]]
Thread 2 releases the lock
At this point, I would expect thread 3 to acquire the lock, but it does
not do it until thread 1 releases its read lock.
This seems to be caused by the "shared_mutex
::unlock_upgrade()" method in thread/pthread/shared_mutex.hpp, that only
calls "release_waiters()" if it is the last reader, ignoring that another
upgrade lock might be waiting to take the lock.
I suppose it could be fixed by maintaining a count of the number of
threads waiting for an upgrade lock, and to signal the shared condition if
this is non-zero.
Here is an example program:
{{{
#include <iostream>
#include <boost/thread.hpp>
class Test
{
public:
void m1()
{
std::cout << "m1 - Trying to take an shared lock" << std::endl;
boost::shared_lock<boost::shared_mutex> lock(_mutex);
std::cout << "m1 - Took a shared lock" << std::endl;
sleep(5);
std::cout << "m1 - Released the lock" << std::endl;
}
void m2()
{
sleep(1);
std::cout << "m2 - Trying to take an upgradable lock" << std::endl;
boost::upgrade_lock<boost::shared_mutex> lock(_mutex);
std::cout << "m2 - Took an upgradable lock" << std::endl;
sleep(1);
std::cout << "m2 - Released an upgradable lock" << std::endl;
}
void m3()
{
sleep(2);
std::cout << "m3 - Trying to take an upgradable lock" << std::endl;
boost::upgrade_lock<boost::shared_mutex> lock(_mutex);
std::cout << "m3 - Took an upgradable lock" << std::endl;
std::cout << "m3 - Releasing locks" << std::endl;
}
void run()
{
boost::thread t1(&Test::m1, this);
boost::thread t2(&Test::m2, this);
m3();
t1.join();
t2.join();
}
private:
boost::shared_mutex _mutex;
};
int main()
{
Test test;
test.run();
return 0;
}
}}}
Results:
{{{
m1 - Trying to take an shared lock
m1 - Took a shared lock
m2 - Trying to take an upgradable lock
m2 - Took an upgradable lock
m3 - Trying to take an upgradable lock
m2 - Released an upgradable lock
m1 - Released the lock
m3 - Took an upgradable lock
m3 - Releasing locks
}}}
Expected:
{{{
m1 - Trying to take an shared lock
m1 - Took a shared lock
m2 - Trying to take an upgradable lock
m2 - Took an upgradable lock
m3 - Trying to take an upgradable lock
m2 - Released an upgradable lock
m3 - Took an upgradable lock
m3 - Releasing locks
m1 - Released the lock
}}}
Tested in Boost 1.42, visually checked that Trunk would have the same
behaviour.
-- Ticket URL: <https://svn.boost.org/trac/boost/ticket/5516> 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:06 UTC