dimanche 12 janvier 2020

Upgrade shared_lock to unique lock usage, timing and design

I am updating a code that previously uses its own read and write lock mechanism (this code was written prior to C++11 and std::shared_mutex does not exist yet) to use the std version of C++.

There is two classes named ReadLock and WriteLock, and ReadLock can be upgraded to WriteLock using method call. WriteLock can also be obtained anytime without upgrade from shared_lock. Reading the C++ std version of shared_lock, i think its straight forward and easy.

ReadLock will just be replaced with shared_lock WriteLock will be replaced with unique_lock and can be triggered anytime calling lock() to obtain a Writelock Upgrade to Writelock will just be performed in two steps unlocking shared_lock and locking unique_lock

My problem now, is when I read thru discussions, there might be specific problems and thread like this raised a concern (thread from Howard Hinnant) Can a shared lock on a std::shared_timed_mutex be upgraded to an exclusive lock?

So I consider using the boost version instead because it supports upgrade_lock and boost::upgrade_to_unique_lock, but i am confuse on how to approach the design on it.

WriteLock class can both represent unique_lock and/or upgrade_lock and upgrade_to_unique_lock objects since as I mentioned above, WriteLock can be attain without shared_lock as well.

Also, I am confuse on how to explicitly trigger lock() and unlock() mechanism if I use upgrade_lock from boost; boost::upgrade_lock has a constructor that accepts defer_lock as parameter and has methods of lock() and unlock() that i can use anytime, but i dont see the same functioanlity if we upgrade it to unique lock using boost::upgrade_to_unique_lock(), creating an object of upgrade_to_unique_lock() automatically converts and lock it.

here is a pseudocode of what I am trying to attain approach 1 basic operation

    void foo()
    {
        ReadLock readLock = someWrapper->AcquireReader();    // return a shared lock
        ...
        WriteLock writeLock = readLock->UpgradeToWriter();   // returns a unique lock
        writeLock->Lock();
        // do something here
    }   // writelock are unlock since constructor is called

approach 2 straight up writelock

    void foo()
    {
        WriteLock writeLock = someWrapper->GetWriter();   // acquire lock straight
        writeLock->Lock();
        // do something here
    }   // writelock are unlock since constructor is called
}

so my questions here are

  1. Is my concern if I use std C++ valid that i need to use boost instead or is C++ std::shared_mutex is enough? In the above sample both UpgradeToWriter() and GetWriter() will just return an object with unique_lock, but Upgrade will just unlock the shared_lock first.
  2. If I use boost version, how should I approach the design as upgrade_to_unique_lock is different type to unique_lock? I was thinking that the WriteLock class both contains definitions of unique_lock, upgrade_lock and boost:upgrade_to_unique_lock and will be locked whether its an upgrade or just a plain get that brings me to my last and final question
  3. How to explicitly or defered/trigger lock for boost:upgrade_to_unique_lock? as it does not have the defer_lock parameter nor the lock() and unlock() method, just the constructor to do his stuff?

from boost sample on usage of boost::upgrade_to_unique_lock , all samples looks like the below code, creating an object automaticaly triggers conversion and lock.

void writer()
{
  // get upgradable access
  boost::upgrade_lock<boost::shared_mutex> lock(_access);

  // get exclusive access
  boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock); // <-- want this to be performed or triggered explicitly, how?
  // now we have exclusive access
}

Thank you in advance, I know there are C++ experts in here that can help a brother out

Aucun commentaire:

Enregistrer un commentaire