Daily bit(e) C++. std::recursive_mutex

Добавлено 25 августа 2023 в 06:41

Daily bit(e) C++ #13, рекурсивный вариант мьютекса: std::recursive_mutex

Daily bit(e) C++. std::recursive_mutex

std::recursive_mutex – это вариант std::mutex, который позволяет одному потоку удерживать несколько блокировок. Другие потоки смогут получить этот мьютекс только после того, как все блокировки будут сняты.

Этот функционал пригодится при разработке потокобезопасных структур данных.

#include <mutex>
#include <thread>
#include <chrono>
#include <span>
#include <algorithm>
#include <iostream>

struct NonRecursive 
{
    void push_back(int value) 
    {
        std::unique_lock lock(mux_);
        // мы уже удерживаем mux_, поэтому не можем вызвать reserve()
        if (size_ == capacity_)
            reserve_impl(capacity_ == 0 ? 64 : capacity_ * 2);
        data_[size_++] = value;
    }
    void reserve(size_t cnt) 
    {
        std::unique_lock lock(mux_);
        reserve_impl(cnt);
    }
private:
    // reserve_impl ожидает, что mux_ будет удержан вызывающим
    void reserve_impl(size_t cnt) 
    {
        auto new_data = std::make_unique<int[]>(cnt);
        std::ranges::copy(std::span(data_.get(), size_), new_data.get());
        data_ = std::move(new_data);
        capacity_ = cnt;
        size_ = std::min(size_, capacity_);
    }
    std::mutex mux_;
    std::unique_ptr<int[]> data_;
    size_t size_ = 0;
    size_t capacity_ = 0;
};

struct Recursive 
{
    void push_back(int value) 
    {
        std::unique_lock lock(mux_);
        // удержание рекурсивного мьютекса несколько раз - ОК
        if (size_ == capacity_)
            reserve(capacity_ == 0 ? 64 : capacity_ * 2);
        data_[size_++] = value;
    }
    void reserve(size_t cnt) 
    {
        std::unique_lock lock(mux_);
        auto new_data = std::make_unique<int[]>(cnt);
        std::ranges::copy(std::span(data_.get(), size_), new_data.get());
        data_ = std::move(new_data);
        capacity_ = cnt;
        size_ = std::min(size_, capacity_);
    }
private:
    std::recursive_mutex mux_;
    std::unique_ptr<int[]> data_;
    size_t size_ = 0;
    size_t capacity_ = 0;
};


int main() 
{
    NonRecursive non;
    for (int i = 0; i < 200; i++) 
    {
        non.push_back(i);
    }
    non.reserve(2);
    Recursive rec;
    for (int i = 0; i < 200; i++) 
    {
        rec.push_back(i);
    }
    rec.reserve(2);
}

Открыть пример на Compiler Explorer.

Теги

C++ / CppDaily bit(e) C++Mutex / МьютексSTL / Standard Template Library / Стандартная библиотека шаблоновМногопоточностьПрограммирование

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.