Source · fairmq/
StateQueue.hpublic header
Defines class fair::mq::StateQueue.
Described in Control a device from code.
1/********************************************************************************2 * Copyright (C) 2019-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *3 * *4 * This software is distributed under the terms of the *5 * GNU Lesser General Public Licence (LGPL) version 3, *6 * copied verbatim in the file "LICENSE" *7 ********************************************************************************/8 9#ifndef FAIRMQSTATEQUEUE_H_10#define FAIRMQSTATEQUEUE_H_11 12#include <chrono>13#include <condition_variable>14#include <fairmq/States.h>15#include <mutex>16#include <queue>17#include <utility> // pair18 19namespace fair::mq {20 21class StateQueue22{23 public:24 StateQueue() = default;25 StateQueue(const StateQueue&) = delete;26 StateQueue(StateQueue&&) = delete;27 StateQueue& operator=(const StateQueue&) = delete;28 StateQueue& operator=(StateQueue&&) = delete;29 ~StateQueue() = default;30 31 fair::mq::State WaitForNext()32 {33 std::unique_lock<std::mutex> lock(fMtx);34 fCV.wait(lock, [this] { return Predicate(); });35 return PopFrontUnsafe();36 }37 38 template<typename Timeout>39 std::pair<bool, fair::mq::State> WaitForNext(Timeout&& duration)40 {41 std::unique_lock<std::mutex> lock(fMtx);42 fCV.wait_for(lock, std::forward<Timeout>(duration), [this] { return Predicate(); });43 return ReturnPairUnsafe();44 }45 46 template<typename CustomPredicate>47 std::pair<bool, fair::mq::State> WaitForNextOrCustom(CustomPredicate&& customPredicate)48 {49 std::unique_lock<std::mutex> lock(fMtx);50 fCV.wait(lock, [this, cp = std::move(customPredicate)] { return Predicate() || cp(); });51 return ReturnPairUnsafe();52 }53 54 template<typename CustomPredicate>55 std::pair<bool, fair::mq::State> WaitForCustom(CustomPredicate&& customPredicate)56 {57 std::unique_lock<std::mutex> lock(fMtx);58 fCV.wait(lock, [cp = std::move(customPredicate)] { return cp(); });59 return ReturnPairUnsafe();60 }61 62 void WaitForState(fair::mq::State state)63 {64 while (WaitForNext() != state) {}65 }66 67 template<typename CustomPredicate>68 void WaitForStateOrCustom(fair::mq::State state, CustomPredicate customPredicate)69 {70 auto next = WaitForNextOrCustom(customPredicate);71 while (!customPredicate() && (next.first && next.second != state)) {72 next = WaitForNextOrCustom(customPredicate);73 }74 }75 76 void Push(fair::mq::State state)77 {78 {79 std::lock_guard<std::mutex> lock(fMtx);80 fStates.push(state);81 }82 fCV.notify_one();83 }84 85 template<typename CustomSignal>86 void Push(fair::mq::State state, CustomSignal&& signal)87 {88 {89 std::lock_guard<std::mutex> lock(fMtx);90 fStates.push(state);91 signal();92 }93 fCV.notify_one();94 }95 96 template<typename CustomSignal>97 void Notify(CustomSignal&& signal)98 {99 {100 std::lock_guard<std::mutex> lock(fMtx);101 signal();102 }103 fCV.notify_one();104 }105 106 template<typename CustomSignal>107 void Locked(CustomSignal&& signal)108 {109 std::lock_guard<std::mutex> lock(fMtx);110 signal();111 }112 113 void Clear()114 {115 std::lock_guard<std::mutex> lock(fMtx);116 fStates = std::queue<fair::mq::State>();117 }118 119 private:120 std::queue<fair::mq::State> fStates;121 std::mutex fMtx;122 std::condition_variable fCV;123 124 // must be called under locked fMtx125 fair::mq::State PopFrontUnsafe()126 {127 fair::mq::State state = fStates.front();128 if (state == fair::mq::State::Error) {129 throw DeviceErrorState("Controlled device transitioned to error state.");130 }131 fStates.pop();132 return state;133 }134 135 // must be called under locked fMtx136 std::pair<bool, fair::mq::State> ReturnPairUnsafe()137 {138 auto const pred = Predicate();139 return {pred, pred ? PopFrontUnsafe() : fair::mq::State::Ok};140 }141 142 // must be called under locked fMtx143 bool Predicate() { return !fStates.empty(); }144};145 146} // namespace fair::mq147 148#endif /* FAIRMQSTATEQUEUE_H_ */