IT박스

boost_shared_mutex (다중 읽기 / 한 번 쓰기)의 예?

itboxs 2020. 7. 26. 12:42
반응형

boost_shared_mutex (다중 읽기 / 한 번 쓰기)의 예?


일부 데이터를 자주 읽어야하고 때로는 해당 데이터가 업데이트되는 멀티 스레드 응용 프로그램이 있습니다. 현재 뮤텍스는 데이터에 안전하게 액세스 할 수 있지만 여러 스레드가 동시에 읽을 수 있기를 원하고 업데이트가 필요할 때만 잠글 수 있기 때문에 비용이 많이 듭니다 (업데이트 스레드는 다른 스레드가 완료 될 때까지 기다릴 수 있음) .

나는 이것이해야한다고 생각 boost::shared_mutex하지만 그것을 사용하는 방법에 대해서는 확실하지 않으며 명확한 예를 찾지 못했습니다.

누구나 내가 시작할 수있는 간단한 예가 있습니까?


다음과 같이 할 것 같습니다.

boost::shared_mutex _access;
void reader()
{
  // get shared access
  boost::shared_lock<boost::shared_mutex> lock(_access);

  // now we have shared access
}

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);
  // now we have exclusive access
}

1800 정보가 다소 정확하지만 몇 가지 수정하고 싶은 문제가 있습니다.

boost::shared_mutex _access;
void reader()
{
  boost::shared_lock< boost::shared_mutex > lock(_access);
  // do work here, without anyone having exclusive access
}

void conditional_writer()
{
  boost::upgrade_lock< boost::shared_mutex > lock(_access);
  // do work here, without anyone having exclusive access

  if (something) {
    boost::upgrade_to_unique_lock< boost::shared_mutex > uniqueLock(lock);
    // do work here, but now you have exclusive access
  }

  // do more work here, without anyone having exclusive access
}

void unconditional_writer()
{
  boost::unique_lock< boost::shared_mutex > lock(_access);
  // do work here, with exclusive access
}

Also Note, unlike a shared_lock, only a single thread can acquire an upgrade_lock at one time, even when it isn't upgraded (which I thought was awkward when I ran into it). So, if all your readers are conditional writers, you need to find another solution.


Since C++ 17 (VS2015) you can use the standard for read-write locks:

#include <shared_mutex>

typedef std::shared_mutex Lock;
typedef std::unique_lock< Lock > WriteLock;
typedef std::shared_lock< Lock > ReadLock;

Lock myLock;


void ReadFunction()
{
    ReadLock r_lock(myLock);
    //Do reader stuff
}

void WriteFunction()
{
     WriteLock w_lock(myLock);
     //Do writer stuff
}

For older version, you can use boost with the same syntax:

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

typedef boost::shared_mutex Lock;
typedef boost::unique_lock< Lock >  WriteLock;
typedef boost::shared_lock< Lock >  ReadLock;

Just to add some more empirical info, I have been investigating the whole issue of upgradable locks, and Example for boost shared_mutex (multiple reads/one write)? is a good answer adding the important info that only one thread can have an upgrade_lock even if it is not upgraded, that is important as it means you cannot upgrade from a shared lock to a unique lock without releasing the shared lock first. (This has been discussed elsewhere but the most interesting thread is here http://thread.gmane.org/gmane.comp.lib.boost.devel/214394)

However I did find an important (undocumented) difference between a thread waiting for an upgrade to a lock (ie needs to wait for all readers to release the shared lock) and a writer lock waiting for the same thing (ie a unique_lock).

  1. The thread that is waiting for a unique_lock on the shared_mutex blocks any new readers coming in, they have to wait for the writers request. This ensures readers do not starve writers (however I believe writers could starve readers).

  2. The thread that is waiting for an upgradeable_lock to upgrade allows other threads to get a shared lock, so this thread could be starved if readers are very frequent.

This is an important issue to consider, and probably should be documented.


Use a semaphore with a count that is equal to the number of readers. Let each reader take one count of the semaphore in order to read, that way they can all read at the same time. Then let the writer take ALL the semaphore counts prior to writing. This causes the writer to wait for all reads to finish and then block out reads while writing.


Great response by Jim Morris, I stumbled upon this and it took me a while to figure. Here is some simple code that shows that after submitting a "request" for a unique_lock boost (version 1.54) blocks all shared_lock requests. This is very interesting as it seems to me that choosing between unique_lock and upgradeable_lock allows if we want write priority or no priority.

Also (1) in Jim Morris's post seems to contradict this: Boost shared_lock. Read preferred?

#include <iostream>
#include <boost/thread.hpp>

using namespace std;

typedef boost::shared_mutex Lock;
typedef boost::unique_lock< Lock > UniqueLock;
typedef boost::shared_lock< Lock > SharedLock;

Lock tempLock;

void main2() {
    cout << "10" << endl;
    UniqueLock lock2(tempLock); // (2) queue for a unique lock
    cout << "11" << endl;
    boost::this_thread::sleep(boost::posix_time::seconds(1));
    lock2.unlock();
}

void main() {
    cout << "1" << endl;
    SharedLock lock1(tempLock); // (1) aquire a shared lock
    cout << "2" << endl;
    boost::thread tempThread(main2);
    cout << "3" << endl;
    boost::this_thread::sleep(boost::posix_time::seconds(3));
    cout << "4" << endl;
    SharedLock lock3(tempLock); // (3) try getting antoher shared lock, deadlock here
    cout << "5" << endl;
    lock1.unlock();
    lock3.unlock();
}

참고URL : https://stackoverflow.com/questions/989795/example-for-boost-shared-mutex-multiple-reads-one-write

반응형