[c++] boost shared_mutex의 예 (여러 읽기 / 쓰기 1 회)?

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

이것이 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
}

또한 shared_lock과 달리 업그레이드되지 않은 경우에도 한 번에 하나의 스레드 만 upgrade_lock을 획득 할 수 있습니다 (만나면 어색하다고 생각했습니다). 따라서 모든 독자가 조건부 작성자 인 경우 다른 솔루션을 찾아야합니다.


답변

C ++ 17 (VS2015)부터 읽기-쓰기 잠금에 표준을 사용할 수 있습니다.

#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
}

이전 버전의 경우 동일한 구문으로 boost를 사용할 수 있습니다.

#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;


답변

좀 더 경험적인 정보를 추가하기 위해 업그레이드 가능한 잠금의 전체 문제와 boost shared_mutex (여러 읽기 / 한 쓰기)의 예를 조사하고 있습니까? 업그레이드되지 않은 경우에도 하나의 스레드 만 upgrade_lock을 가질 수 있다는 중요한 정보를 추가하는 좋은 대답입니다. 이는 공유 잠금을 먼저 해제하지 않고는 공유 잠금에서 고유 잠금으로 업그레이드 할 수 없다는 것을 의미하므로 중요합니다. (이것은 다른 곳에서 논의되었지만 가장 흥미로운 스레드는 여기 http://thread.gmane.org/gmane.comp.lib.boost.devel/214394입니다. )

그러나 잠금 업그레이드를 기다리는 스레드 (즉, 모든 독자가 공유 잠금을 해제 할 때까지 기다려야 함)와 동일한 것을 기다리는 작성자 잠금 (예 : unique_lock) 사이에 중요한 (문서화되지 않은) 차이점을 발견했습니다.

  1. shared_mutex에서 unique_lock을 기다리는 스레드는 들어오는 모든 새 리더를 차단하므로 작성자 요청을 기다려야합니다. 이것은 독자가 작가를 굶주 리지 않도록 보장합니다 (하지만 작가가 독자를 굶주릴 수 있다고 믿습니다).

  2. upgradeable_lock이 업그레이드되기를 기다리는 스레드는 다른 스레드가 공유 잠금을 얻을 수 있도록 허용하므로 독자가 매우 빈번한 경우이 스레드가 고갈 될 수 있습니다.

이것은 고려해야 할 중요한 문제이며 아마도 문서화되어야합니다.


답변

판독기 수와 동일한 수의 세마포어를 사용하십시오. 각 독자가 읽기 위해 세마포어의 한 카운트를 가져 와서 동시에 읽을 수 있도록합니다. 그런 다음 작가가 쓰기 전에 모든 세마포어 카운트를 가져 오도록합니다. 이로 인해 작성기는 모든 읽기가 완료 될 때까지 기다린 다음 쓰는 동안 읽기를 차단합니다.


답변

Jim Morris의 큰 반응, 나는 이것을 우연히 발견했고 알아내는 데 시간이 걸렸습니다. 다음은 unique_lock 부스트 (버전 1.54)에 대한 “요청”을 제출 한 후 모든 shared_lock 요청을 차단하는 것을 보여주는 간단한 코드입니다. unique_lock과 upgradeable_lock 중 하나를 선택하면 쓰기 우선 순위를 원하는지 또는 우선 순위가 없는지 선택할 수 있다는 점이 매우 흥미 롭습니다.

또한 (1) Jim Morris의 게시물에서 이것이 모순되는 것 같습니다 :
Boost shared_lock. 읽기 선호?

#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();
}


답변