Ежедневный бит (е) C++ # 15, мьютекс с общими блокировками: std::shared_mutex
std::shared_mutex
— это вариант std::mutex
C++14 (C++17 для версии без синхронизации) std::mutex
, который поддерживает два типа блокировок: монопольную блокировку, которая может удерживаться только одним потоком, и общую блокировку, которая может удерживаться любым потоком. количество потоков (пока эксклюзивная блокировка не удерживается).
Это семантика, обычно необходимая для доступа для чтения и записи, поскольку операции чтения могут выполняться параллельно, а операции записи требуют монопольного доступа.
#include <mutex> #include <shared_mutex> #include <array> #include <optional> struct Data {}; struct RecentSnapshots { void push(const Data& data) { // We are about to modify the data, grab a unique_lock std::unique_lock lock(mux_); buffer_[offset_ % 64] = data; ++offset_; } std::optional<Data> get(size_t index) const { // We only read, but need to prevent // concurrent writes, grab a shared_lock std::shared_lock lock(mux_); if (index >= offset_) return std::nullopt; if (offset_ >= 64 && offset_-64 > index) return std::nullopt; return buffer_[index % 64]; } size_t min_offset() const { // We only read, but need to prevent // concurrent writes, grab a shared_lock std::shared_lock lock(mux_); if (offset_ <= 64) return 0; return offset_ - 64; } private: // We need mutable, since we mutate the state // of this mutex (by grabbing a lock) in const methods. mutable std::shared_mutex mux_; std::array<Data,64> buffer_; size_t offset_ = 0; }; // Note: calling min_offset() followed by get(offset) // does NOT provide any transactionality, as a write can interject // itself between the two calls.