跳轉到內容

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

已知用法

[編輯 | 編輯原始碼]
[編輯 | 編輯原始碼]

參考文獻

[編輯 | 編輯原始碼]
  1. Timour, Doumler. "一個無鎖原子 shared_ptr ACCU 2022" (PDF).
華夏公益教科書