Suppose I have a boost::upgrade_lock<boost::shared_mutex>. When I want to create the boost::upgrade_to_unique_lock<boost::shared_mutex> and upgrade to exclusive locking, this blocks until all the shared lock holders leave. However, it does not appear that there is a non-blocking version of this, unlike, say, making a boost::unique_lock<boost::shared_mutex> and passing in boost::try_to_lock. So what should I do in order to create my own "try-upgrade" lock? I'm trying to use it like so: boost::upgrade_lock<boost::shared_mutex> upgradeLock(mutex); ... if (...) { // Substitute for boost::upgrade_to_unique_lock<boost::shared_mutex>, but also with aspects of // boost::try_to_lock, basically my_upgrade_to_unique_lock<boost::shared_mutex> deferredWriteLock(lock); // Do stuff where it doesn't matter whether I have exclusive or not, while the readers leave if (!deferredWriteLock) deferredWriteLock.lock(); // Now we need exclusive // We have exclusive, do more stuff } // Back to regular upgrade_lock here
Le 13/12/11 18:57, Kelvin Chung a écrit :
Suppose I have a boost::upgrade_lock<boost::shared_mutex>. When I want to create the boost::upgrade_to_unique_lock<boost::shared_mutex> and upgrade to exclusive locking, this blocks until all the shared lock holders leave. However, it does not appear that there is a non-blocking version of this, unlike, say, making a boost::unique_lock<boost::shared_mutex> and passing in boost::try_to_lock.
So what should I do in order to create my own "try-upgrade" lock? I'm trying to use it like so:
boost::upgrade_lock<boost::shared_mutex> upgradeLock(mutex); ... if (...) { // Substitute for boost::upgrade_to_unique_lock<boost::shared_mutex>, but also with aspects of // boost::try_to_lock, basically my_upgrade_to_unique_lock<boost::shared_mutex> deferredWriteLock(lock);
// Do stuff where it doesn't matter whether I have exclusive or not, while the readers leave if (!deferredWriteLock) deferredWriteLock.lock(); // Now we need exclusive // We have exclusive, do more stuff } // Back to regular upgrade_lock here
Hi, There is a draft proposal from Howard Hinnant "Shared locking in C++" http://home.roadrunner.com/~hinnant/bloomington/shared_mutex.html that doesn't have upgrade_to_unique_lock but that allows to try to lock an upgrade_lock. Even if the interface is a little bit different I guess that the lecture will help you a lot. If I understand you wan to lock a mutex with shared ownership until you need to have exclusive ownership and then retrieve the shard ownership again. Unfortunately I think that the current interface doesn't let you to try to move from shared to exclusive ownership without blocking, and I don't know how to move from a exclusive ownership to a shared on. If you can block when getting exclusive ownership, you will be able to implement it with the current interface as follows (Note pseudo-code) IUC, Howard's proposal contains all the ingredient to do it using a an initial shared_lock, trying to move to an upgrade_lock and if successful moving then to a unique_lock and last moving back to the initial shared_lock. See the example: upgrade_mutex mut; // ... void foo() { shared_lock<upgrade_mutex> sl(mut); // mut share locked here // ... // Try to convert mut from shared to upgrade ownership for 5ms // It can succeed if no other thread has upgrade ownership, // or is blocked on exclusive ownership. upgrade_lock<upgrade_mutex> ul(std::move(sl), chrono::milliseconds(5)); if (ul.owns_lock()) { // mut upgrade locked here // This thread will still share with other threads having shared ownership here. // ... // Convert mut from upgrade to exclusive, blocking as necessary unique_lock<upgrade_mutex> el(std::move(ul)); // mut exclusive locked here // No other threads have shared, upgrade or exclusive ownership here. // ... }// mut.unlock() else { // mut still share locked here // ... } }// if mut is share locked, then mut.unlock_shared() I plan to adapt it to boost as a replacement of the current Boost.Thread/Boost.Interprocess implementation, but this will take some time. In the mean time you can create some feature requests, I will try to get them, but I really think the design must be changed globally. Best, Vicente
On Dec 13, 2011, at 5:37 PM, Vicente J. Botet Escriba wrote:
Le 13/12/11 18:57, Kelvin Chung a écrit :
Suppose I have a boost::upgrade_lock<boost::shared_mutex>. When I want to create the boost::upgrade_to_unique_lock<boost::shared_mutex> and upgrade to exclusive locking, this blocks until all the shared lock holders leave. However, it does not appear that there is a non-blocking version of this, unlike, say, making a boost::unique_lock<boost::shared_mutex> and passing in boost::try_to_lock.
So what should I do in order to create my own "try-upgrade" lock? I'm trying to use it like so:
boost::upgrade_lock<boost::shared_mutex> upgradeLock(mutex); ... if (...) { // Substitute for boost::upgrade_to_unique_lock<boost::shared_mutex>, but also with aspects of // boost::try_to_lock, basically my_upgrade_to_unique_lock<boost::shared_mutex> deferredWriteLock(lock);
// Do stuff where it doesn't matter whether I have exclusive or not, while the readers leave if (!deferredWriteLock) deferredWriteLock.lock(); // Now we need exclusive // We have exclusive, do more stuff } // Back to regular upgrade_lock here
Hi,
There is a draft proposal from Howard Hinnant "Shared locking in C++" http://home.roadrunner.com/~hinnant/bloomington/shared_mutex.html that doesn't have upgrade_to_unique_lock but that allows to try to lock an upgrade_lock. Even if the interface is a little bit different I guess that the lecture will help you a lot.
If I understand you wan to lock a mutex with shared ownership until you need to have exclusive ownership and then retrieve the shard ownership again. Unfortunately I think that the current interface doesn't let you to try to move from shared to exclusive ownership without blocking, and I don't know how to move from a exclusive ownership to a shared on.
If you can block when getting exclusive ownership, you will be able to implement it with the current interface as follows (Note pseudo-code)
IUC, Howard's proposal contains all the ingredient to do it using a an initial shared_lock, trying to move to an upgrade_lock and if successful moving then to a unique_lock and last moving back to the initial shared_lock. See the example:
upgrade_mutex mut;
// ...
void foo() { shared_lock<upgrade_mutex> sl(mut);
// mut share locked here
// ...
// Try to convert mut from shared to upgrade ownership for 5ms
// It can succeed if no other thread has upgrade ownership,
// or is blocked on exclusive ownership.
upgrade_lock<upgrade_mutex> ul(std::move(sl), chrono::milliseconds(5)); if (ul.owns_lock()) {
// mut upgrade locked here
// This thread will still share with other threads having shared ownership here.
// ...
// Convert mut from upgrade to exclusive, blocking as necessary
unique_lock<upgrade_mutex> el(std::move(ul));
// mut exclusive locked here
// No other threads have shared, upgrade or exclusive ownership here.
// ...
} // mut.unlock()
else {
// mut still share locked here
// ...
} } // if mut is share locked, then mut.unlock_shared()
I plan to adapt it to boost as a replacement of the current Boost.Thread/Boost.Interprocess implementation, but this will take some time.
In the mean time you can create some feature requests, I will try to get them, but I really think the design must be changed globally.
If it helps anyone, here's my latest implementation: http://home.roadrunner.com/~hinnant/mutexes/shared_mutex http://home.roadrunner.com/~hinnant/mutexes/shared_mutex.cpp There are probably bits in there that are libc++-specific. Haven't looked at it in awhile. But it is boost-open-sourced (not part of the boost library), and anyone who wants it is welcome to it. Howard
participants (3)
-
Howard Hinnant
-
Kelvin Chung
-
Vicente J. Botet Escriba