/** * @file src/single_flight.h * @brief Admit one queued or running operation without blocking its callers. */ #pragma once #include #include #include namespace single_flight { class admission_t { struct lease_t { std::shared_ptr busy; ~lease_t() { busy->store(false, std::memory_order_release); } }; std::shared_ptr busy_ = std::make_shared(false); public: template bool try_submit(Submit &&submit, Task &&task) { if (busy_->exchange(true, std::memory_order_acq_rel)) { return false; } std::shared_ptr lease; try { lease = std::make_shared(); } catch (...) { busy_->store(false, std::memory_order_release); throw; } lease->busy = busy_; std::forward(submit)([lease = std::move(lease), task = std::forward(task)]() mutable { // Release when execution ends, even if the executor retains the task // object or the operation throws. A discarded queued task releases too. auto running = std::move(lease); task(); }); return true; } }; } // namespace single_flight