1

I was wondering what the difference is in boost::shared_mutex and boost::upgrade_mutex. I wanted to make a multi threaded application that will have multiple frequent readers and one non frequent writer.

I could just use a standard shared_mutex and a shared_lock and a unique_lock. Although this is likely to give me writer starvation.

What I want is: If a reader has a shared lock and a writer is waiting on the lock that no other readers will be given access and they will have to wait on the shared lock.

I can find very little information on boost::upgrade_mutex, but I think this is what I want?

I made this example (please ignore that the couts are happening outside of a lock etc and that I can't control which thread runs first):

#include <iostream>
#include <thread>

#include <boost/thread/locks.hpp>
#include <boost/thread/shared_mutex.hpp>

int main()
{
    boost::shared_mutex mutex;

    boost::shared_lock<boost::shared_mutex> read_lock(mutex);

    std::thread t1([&mutex]()
    {
        std::cout << "Thread trying to get the unique lock!" << std::endl;
        boost::unique_lock<boost::shared_mutex> write_lock(mutex);
        std::cout << "Thread got the unique lock!" << std::endl;
    });

    std::thread t2([&mutex]()
    {
        std::cout << "Thread trying to get the shared lock!" << std::endl;
        boost::shared_lock<boost::shared_mutex> read_lock(mutex);
        std::cout << "Thread got the shared lock!" << std::endl;
    });

    // To make sure the threads ask for the lock before unlocking
    sleep(1);

    std::cout << "Unlocking first lock" << std::endl;
    read_lock.unlock();

    t1.join();
    t2.join();
}

From my testing, if t1 runs before t2, t2 also waits on read_lock.unlock(); before proceeding. This is what I want!

I then changed boost::upgrade_mutex to boost::shared_mutex (in the template param of the locks as well) and I am seeing exactly the same behaviour. I can't find in the documentation if this is guaranteed or what the difference is.

av4625
  • 303
  • 1
  • 11

1 Answers1

1

Reading the documentation, the upgrade_mutex is a shared_mutex with extra functionality considered upgrading. See https://www.boost.org/doc/libs/1_81_0/doc/html/thread/synchronization.html#thread.synchronization.mutex_concepts.upgrade_lockable

The UpgradeLockable concept is a refinement of the SharedLockable concept that allows for upgradable ownership as well as shared ownership and exclusive ownership. This is an extension to the multiple-reader / single-write model provided by the SharedLockable concept: a single thread may have upgradable ownership at the same time as others have shared ownership. The thread with upgradable ownership may at any time attempt to upgrade that ownership to exclusive ownership. If no other threads have shared ownership, the upgrade is completed immediately, and the thread now has exclusive ownership, which must be relinquished by a call to unlock(), just as if it had been acquired by a call to lock().

The thing you cannot do with shared_lock is upgrading from shared locking to unique locking, without unlocking. The upgrade_lock is something in-between a shared and a unique lock. You can only have a single upgrade lock, though at the same time multiple shared locks can be taken. You can ask to upgrade the upgrade lock to a unique lock, which will only succeed after all shared locks are released. (Other operations are also possible, though they are less relevant to understand the difference)

JVApen
  • 11,008
  • 5
  • 31
  • 67
  • I think that means I don't need the upgrade_mutex as I am not upgrading a reader to a writer, the writers only write. I just need to ensure that `shared_mutex` actually does guarantee: `If a reader has a shared lock and a writer is waiting on the lock that no other readers will be given access and they will have to wait on the shared lock` – av4625 Feb 19 '23 at 19:24
  • I think that describes the lock like `boost::upgrade_lock lock(...);` rather than the mutex itself, unless this is what I'm getting confused with. Any example I see people using an `upgrade_lock` with a `shared_mutex` like the accepted answer here: https://stackoverflow.com/questions/3896717/example-of-how-to-use-boost-upgradeable-mutexes – av4625 Feb 19 '23 at 20:01
  • If this is anything like the standard mutexes (which can safely assume in this case), mutex and lock go hand in hand. Upgrade lock will use certain methods and as it is a template won't fail on methods which ain't used. – JVApen Feb 19 '23 at 20:15