Program Listing for File barrier.hpp¶
↰ Return to documentation for file (include/uitsl/polyfill/barrier.hpp)
#pragma once
#ifndef UITSL_POLYFILL_BARRIER_HPP_INCLUDE
#define UITSL_POLYFILL_BARRIER_HPP_INCLUDE
#include <condition_variable>
#include <cstddef>
// polyfill until C++20 barrier becomes available
// TODO C++20 cpp20 switch to std::barrier
namespace std {
// adapted from
// https://github.com/llvm/llvm-project/blob/bcf14f375e29b94e7abb381920df795eeefb2309/libcxx/include/barrier
struct EmptyCompletion
{
void operator()() noexcept { ; }
};
/*
The alternative implementation of __barrier_base is a central barrier.
Two versions of this algorithm are provided:
1. A fairly straightforward implementation of the litterature for the
general case where the completion function is not empty.
2. An optimized implementation that exploits 2's complement arithmetic
and well-defined overflow in atomic arithmetic, to handle the phase
roll-over for free.
*/
template<class OnCompletion=EmptyCompletion>
class barrier {
public:
using arrival_token = bool;
private:
ptrdiff_t expected;
ptrdiff_t arrived;
OnCompletion on_completion;
bool phase{false};
mutable std::condition_variable cv;
mutable std::mutex mutex;
arrival_token arrive() {
const std::lock_guard<std::mutex> lock{mutex};
constexpr ptrdiff_t update{1};
arrived -= update;
const auto old_phase = phase;
if (arrived == 0) {
on_completion();
arrived = expected;
phase = !phase;
cv.notify_all();
}
return old_phase;
}
public:
static constexpr ptrdiff_t max() noexcept {
return std::numeric_limits<ptrdiff_t>::max();
}
barrier(
const ptrdiff_t expected_,
const OnCompletion on_completion_ = OnCompletion{}
) : expected(expected_)
, arrived(expected_)
, on_completion(std::move(on_completion_))
{ ; }
void wait(arrival_token&& old_phase) const {
std::unique_lock<std::mutex> lock{mutex};
cv.wait(
lock,
[this, old_phase](){ return phase != old_phase; }
);
}
void arrive_and_wait() { wait(arrive()); }
void arrive_and_drop() {
{
const std::lock_guard<std::mutex> lock{mutex};
--expected;
}
arrive();
}
};
} // namespace uitsl
#endif // #ifndef UITSL_POLYFILL_BARRIER_HPP_INCLUDE