30template <
typename Task, std::
size_t Capacity = 64>
32 static_assert(std::is_trivially_copyable_v<Task>,
33 "RT task payloads must be trivially copyable");
35 using Handler = void (*)(
void*,
const Task&);
48 HandlerFunction([handler, context](
const Task& task) { handler(context, task); }),
54 if (!handler || running_.load(std::memory_order_acquire))
return false;
55 handler_ = std::move(handler);
57 latest_generation_.store(0, std::memory_order_relaxed);
58 stopping_.store(
false, std::memory_order_release);
60 worker_ = std::thread([
this] { worker_loop(); });
65 running_.store(
true, std::memory_order_release);
70 stopping_.store(
true, std::memory_order_release);
71 if (worker_.joinable()) worker_.join();
72 running_.store(
false, std::memory_order_release);
76 if (!running_.load(std::memory_order_acquire))
return false;
79 latest_generation_.fetch_add(1, std::memory_order_release);
82 return ordered_.try_push(task);
85 bool running() const noexcept {
return running_.load(std::memory_order_acquire); }
86 std::uint64_t
overflow_count() const noexcept {
return ordered_.overflow_count(); }
89 void worker_loop() noexcept {
90 std::uint64_t consumed_generation = 0;
91 while (!stopping_.load(std::memory_order_acquire)) {
94 const auto generation = latest_generation_.load(std::memory_order_acquire);
95 if (generation != consumed_generation) {
96 invoke(latest_.
read());
97 consumed_generation = generation;
100 }
else if (
auto task = ordered_.try_pop()) {
104 if (!handled) std::this_thread::sleep_for(std::chrono::milliseconds(1));
107 while (
auto task = ordered_.try_pop()) invoke(*task);
109 const auto generation = latest_generation_.load(std::memory_order_acquire);
110 if (generation != consumed_generation) invoke(latest_.read());
114 void invoke(
const Task& task)
noexcept {
121 runtime::SpscQueue<Task, Capacity> ordered_;
122 runtime::TripleBuffer<Task> latest_;
123 std::atomic<std::uint64_t> latest_generation_{0};
124 std::atomic<bool> running_{
false};
125 std::atomic<bool> stopping_{
false};
Definition fixed_function.hpp:42
const T & read() noexcept
Read the latest published value from the reader thread.
Definition triple_buffer.hpp:88
Portable try/catch macros for source that must also compile with C++ exceptions disabled (-fno-except...
#define PULP_TRY
Definition exceptions.hpp:42
#define PULP_CATCH_ALL
Definition exceptions.hpp:43
FixedFunction<Signature, Capacity> - a move-only callable wrapper with inline storage that never touc...
Lock-free latest-value publication between two threads.