boost::shared_mutex
或std::shared_mutex
(C++ 17)可以用於單個寫入器,多個讀取器訪問。作爲一個教育練習,我將一個使用spinlocking的簡單實現放在一起,並具有其他限制(例如公平性策略),但顯然不打算用於實際應用。C++ shared_mutex實現
這個想法是,如果沒有線程持有鎖,互斥量會保持爲零的引用計數。如果> 0,則該值表示有權訪問的讀取器的數量。如果-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的無序內核的副本。) –