更多 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).