일부 데이터를 자주 읽고 가끔 데이터가 업데이트되는 멀티 스레드 앱이 있습니다. 현재 뮤텍스는 해당 데이터에 대한 액세스를 안전하게 유지하지만 여러 스레드가 동시에 읽을 수 있고 업데이트가 필요할 때만 잠글 수 있기 때문에 비용이 많이 듭니다 (업데이트 스레드는 다른 스레드가 완료 될 때까지 기다릴 수 있음). .
이것이 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) 사이에 중요한 (문서화되지 않은) 차이점을 발견했습니다.
-
shared_mutex에서 unique_lock을 기다리는 스레드는 들어오는 모든 새 리더를 차단하므로 작성자 요청을 기다려야합니다. 이것은 독자가 작가를 굶주 리지 않도록 보장합니다 (하지만 작가가 독자를 굶주릴 수 있다고 믿습니다).
-
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();
}