Reading write lock function in C ++

I am trying to use read / write lock in C ++ using shared_mutex

typedef boost::shared_mutex Lock; typedef boost::unique_lock< Lock > WriteLock; typedef boost::shared_lock< Lock > ReadLock; class Test { Lock lock; WriteLock writeLock; ReadLock readLock; Test() : writeLock(lock), readLock(lock) {} readFn1() { readLock.lock(); /* Some Code */ readLock.unlock(); } readFn2() { readLock.lock(); /* Some Code */ readLock.unlock(); } writeFn1() { writeLock.lock(); /* Some Code */ writeLock.unlock(); } writeFn2() { writeLock.lock(); /* Some Code */ writeLock.unlock(); } } 

The code seems to work fine, but I have a few conceptual questions.

Q1. I saw recommendations for using unique_lock and shared_lock at http://en.cppreference.com/w/cpp/thread/shared_mutex/lock , but I don’t understand why, since shared_mutex already supports lock and lock_shared methods?

Q2. Can this code cause hunger? If so, how can I avoid starvation?

Q3. Is there any other lock class that I can try to implement write write lock?

+5
source share
3 answers

Q1: using mutex shell

It is recommended that you use the wrapper object instead of directly controlling the mutex to avoid an unfortunate situation where your code is interrupted and the mutex has not been released and it remains locked forever.

This is the principle of RAII .

But this only works if your ReadLock or WriteLock is local to the function you are using.

Example:

 readFn1() { boost::unique_lock< Lock > rl(lock); /* Some Code ==> imagine exception is thrown */ rl.unlock(); // this is never reached if exception thrown } // fortunately local object are destroyed automatically in case // an excpetion makes you leave the function prematurely 

In your code, this will not work if one of the functions is mixed up, because your ReadLock WriteLock object is a member of Test, and not local to the function that sets the lock.

Q2: record fasting

It’s not entirely clear how you will refer to readers and writers, but yes, there is a risk:

  • as long as readers are active, the record is blocked by a unique block, expecting the mutex to be interesting in exclusive mode.
  • however, while the user is waiting, new readers can access the general lock, as a result of which unique_lock will be delayed.

If you want to avoid starvation, you must make sure that pending authors get the opportunity to set their unique_lock. For example, take some code in your readers to check if the writer is waiting before locking.

Q3 Other lock classes

Not quite sure what you are looking for, but I have the impression that condition_variable might interest you. But the logic is a little different.

Perhaps you can also find a solution by thinking “out of the box”: perhaps there is a suitable data structure without blocking that could facilitate the coexistence of readers and writers by slightly changing the approach?

+2
source

Lock types are fine, but instead of creating them as member functions, then inside locktype lock(mymutex) functions locktype lock(mymutex) . Thus, they are released upon destruction, even in the event of an exception.

+2
source

Q1. I saw recommendations for using unique_lock and shared_lock at http://en.cppreference.com/w/cpp/thread/shared_mutex/lock , but I don’t understand why, since shared_mutex already supports lock and lock_shared methods?

Perhaps because unique_lock has existed since C ++ 11, but shared_lock comes on board with C ++ 17. In addition, [maybe] unique_lock can be more efficient. Here's the original rationale for shared_lock [by the creator] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2406.html , and I rely on that.

Q2. Can this code cause hunger? If so, how can I avoid starvation?

Yes, absolutely. If you do:

 while (1) writeFn1(); 

You can get the time string:

 T1: writeLock.lock() T2: writeLock.unlock() T3: writeLock.lock() T4: writeLock.unlock() T5: writeLock.lock() T6: writeLock.unlock() ... 

The difference T2-T1 arbitrary, based on the amount of work performed. But T3-T2 is close to zero. This is a window for another thread to get a lock. Since the window is so small, it probably won’t get it.

To solve this problem, the easiest way is to insert a little dream (like nanosleep ) between T2 and T3 . You can do this by adding it to the end of writeFn1 .

Other methods may include creating a queue for locking. If the thread cannot get the lock, it adds itself to the queue, and the first thread in the queue gets the lock when the lock is released. In the linux kernel, this is implemented for "queued spinlock"

Q3. Is there any other lock class that I can try to implement write write lock?

While not a class, you can use pthread_mutex_lock and pthread_mutex_unlock . They implement recursive locks. You can add your own code to implement the boost::scoped_lock . Your class can control semantics.

Or, boost has its own locks.

+1
source

Source: https://habr.com/ru/post/1243709/


All Articles