boost::shared_mutex
またはstd::shared_mutex
(C++ 17)は、シングルライター、複数リーダーアクセスに使用できます。教育上の練習として、私はスピンロックを使用し、他の制限がある(例えば公平性ポリシー)単純な実装を組み立てましたが、実際のアプリケーションでは使用されないことは明らかです。C++ shared_mutexの実装
スレッドがロックを保持していない場合、ミューテックスは参照カウントをゼロに保つという考えがあります。 > 0の場合、値はアクセス権を持つ読者の数を表します。 -1の場合、1つのライターがアクセス権を持ちます。
これは、データレースのない正しい実装(特に、使用されている最小限のメモリ順序)ですか?
#include <atomic>
class my_shared_mutex {
std::atomic<int> refcount{0};
public:
void lock() // write lock
{
int val;
do {
val = 0; // Can only take a write lock when refcount == 0
} while (!refcount.compare_exchange_weak(val, -1, std::memory_order_acquire));
// can memory_order_relaxed be used if only a single thread takes write locks ?
}
void unlock() // write unlock
{
refcount.store(0, std::memory_order_release);
}
void lock_shared() // read lock
{
int val;
do {
do {
val = refcount.load(std::memory_order_relaxed);
} while (val == -1); // spinning until the write lock is released
} while (!refcount.compare_exchange_weak(val, val+1, std::memory_order_acquire));
}
void unlock_shared() // read unlock
{
refcount.fetch_sub(1, std::memory_order_relaxed);
}
};
私はunlock_sharedのメモリの順序についてはわかりませんでしたが、私の推論は、読み取り専用のアクセスしか持たず、保護するデータを変更できないため、実際には何もリリースしていないということでした。 – LWimsey
@LWimsey:店舗の注文よりも荷物の発注について考えることができますが、それは本当のことです。 L1キャッシュからデータを読み込んだ時点で、負荷は全体的に可視になります。 (これは、グローバルコヒーレントキャッシュから単一のCPUのアウトオブオーダーコアへのコピーを作成するためです。) –