Daily bit(e) C++. std::recursive_mutex
Добавлено 25 августа 2023 в 06:41
Daily bit(e) C++ #13, рекурсивный вариант мьютекса: 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.