|
||||
File indexing completed on 2025-01-18 10:01:39
0001 0002 // Copyright 2020, Jefferson Science Associates, LLC. 0003 // Subject to the terms in the LICENSE file found in the top-level directory. 0004 0005 0006 #ifndef JANA2_JEVENTGROUPTRACKER_H 0007 #define JANA2_JEVENTGROUPTRACKER_H 0008 0009 #include <JANA/Services/JServiceLocator.h> 0010 #include <JANA/JObject.h> 0011 0012 #include <atomic> 0013 #include <thread> 0014 0015 /// A persistent JObject 0016 class JEventGroup : public JObject { 0017 0018 const int m_group_id; 0019 mutable std::atomic_int m_events_in_flight; 0020 mutable std::atomic_bool m_group_closed; 0021 0022 friend class JEventGroupManager; 0023 0024 /// Construction of JEventGroup is restricted to JEventGroupManager. This enforces the 0025 /// invariant that pointer equality <=> group_id, assuming a singleton JEventGroupManager. 0026 explicit JEventGroup(int group_id) : m_group_id(group_id), 0027 m_events_in_flight(0), 0028 m_group_closed(true) {} 0029 0030 public: 0031 0032 /// Report back what group this actual is. This is mostly for debugging purposes. 0033 int GetGroupId() const { 0034 return m_group_id; 0035 } 0036 0037 /// Record that another event belonging to this group has been emitted. 0038 /// This is meant to be called from JEventSource::GetEvent. 0039 void StartEvent() const { 0040 m_events_in_flight += 1; 0041 m_group_closed = false; 0042 } 0043 0044 /// Report an event as finished. If this was the last event in the group, IsGroupFinished will now return true. 0045 /// Please only call once per event, so that we don't have to maintain a set of outstanding event ids. 0046 /// This takes advantage of C++ atomics to detect if _we_ were the one who finished the whole group without 0047 /// needing a lock. 0048 /// This is meant to be called from JEventProcessor::Process. 0049 bool FinishEvent() const { 0050 auto prev_events_in_flight = m_events_in_flight.fetch_sub(1); 0051 assert(prev_events_in_flight > 0); // detect if someone is miscounting 0052 return (prev_events_in_flight == 1) && m_group_closed; 0053 } 0054 0055 /// Indicate that no more events in the group are on their way. Note that groups can be re-opened 0056 /// by simply emitting another event tagged according to that group. 0057 /// This is meant to be called from JEventSource::GetEvent. 0058 void CloseGroup() const { 0059 m_group_closed = true; 0060 } 0061 0062 /// Test whether all events in the group have finished. Two conditions have to hold: 0063 /// 1. The number of in-flight events must be zero 0064 /// 2. The group must be closed. Otherwise, if the JEventSource is slow but the JEventProcessor is fast, 0065 /// the number of in-flight events could drop to zero before the group is conceptually finished. 0066 /// This is meant to be callable from any JANA component. 0067 /// Note that this doesn't indicate anything about _who_ 0068 bool IsGroupFinished() const { 0069 return m_group_closed && (m_events_in_flight == 0); 0070 } 0071 0072 /// Block until every event in this group has finished, and the eventsource has declared the group closed. 0073 /// This is meant to be callable from any JANA component. 0074 void WaitUntilGroupFinished() { 0075 while (!(m_group_closed && (m_events_in_flight == 0))) { 0076 std::this_thread::sleep_for(std::chrono::milliseconds(10)); 0077 } 0078 } 0079 }; 0080 0081 /// JEventGroupManager is a JService which 0082 /// The purpose of JEventGroupManager is to 0083 /// 1. Maintain ownership over all JEventGroup objects, ensuring that the pointers live the entire 0084 /// duration of JApplication::Run() and are always deleted afterwards. 0085 /// 2. Enforce the invariant where any two objects with the same identity (i.e. pointer equality) have 0086 /// equal group ids. This makes debugging much easier. 0087 /// 3. Encourage the practice of keeping state which is shared between different JEvents _explicit_ by using JServices. 0088 0089 class JEventGroupManager final : public JService { 0090 0091 std::mutex m_mutex; 0092 std::map<int, JEventGroup*> m_eventgroups; 0093 0094 public: 0095 ~JEventGroupManager() final { 0096 for (auto item : m_eventgroups) { 0097 delete item.second; 0098 } 0099 } 0100 0101 JEventGroup* GetEventGroup(int group_id) { 0102 std::lock_guard<std::mutex> lock(m_mutex); 0103 auto result = m_eventgroups.find(group_id); 0104 if (result == m_eventgroups.end()) { 0105 auto* eg = new JEventGroup(group_id); 0106 m_eventgroups.insert(std::make_pair(group_id, eg)); 0107 return eg; 0108 } 0109 else { 0110 return result->second; 0111 } 0112 } 0113 0114 }; 0115 0116 0117 #endif //JANA2_JEVENTGROUPTRACKER_H
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |