更多 C++ 慣用法/執行緒安全寫時複製
外觀
允許物件以併發安全的方式快速訪問,無需必要複製,最好是在沒有鎖的情況下。
許多應用程式允許在執行時進行配置更改,但併發地將更改應用到系統需要快速同步原語。普遍存在的互斥,可能會阻塞正在執行的執行緒,對於像遊戲引擎這樣的延遲敏感應用程式不是可行的解決方案。此慣用法是流行的互斥的替代方案,適用於讀取很常見而寫入很少見的情況。讀取路徑很快並且從不阻塞,但增量寫入可能需要互斥。
#pragma once
#include <atomic>
#include <memory>
#include <folly/concurrency/AtomicSharedPtr.h>
template <typename ValT, typename KeyT>
class ThreadSafeCowPtr {
public:
using DataT = std::unordered_map<KeyT, ValT>;
ThreadSafeCowPtr() : data{std::make_shared<DataT>()} {
assert(data.is_lock_free());
}
std::shared_ptr<DataT> read() {
return data.load();
}
void write(std::shared_ptr<DataT> new_ptr) {
// does not require mutex if we don't care about previous content
data.store(new_ptr);
}
// Copy on write
void update(const KeyT& key, const ValT& val) {
// note that update() operation requires mutex to guarantee that
// multiple threads calling update() won't drop any data
std::lock_guard<std::mutex> lock(update_mut);
auto new_ptr = std::make_shared<DataT>(*this->read()); // assume valid
new_ptr->emplace(key, val);
this->write(new_ptr);
}
private:
std::mutex update_mut;
folly::atomic_shared_ptr<DataT> data;
};
此實現依賴於以下事實:庫 folly 提供無鎖原子共享指標。並非所有庫都提供無鎖智慧指標,即使原子特化可用。即,c++ 標準庫不提供無鎖原子指標[1]。以下程式碼將不會評估為真。
std::shared_ptr<int> obj;
assert(std::atomic(obj).is_lock_free()); // fails as of c++20
- ↑ Timour, Doumler. "一個無鎖原子 shared_ptr ACCU 2022" (PDF).