gdata
Loading...
Searching...
No Matches
gdata_event_example.cc
Go to the documentation of this file.
1
25// gdata
27
28// gemc
29#include "glogger.h"
30
31
32// TODO: remove when C++20 is widely available
33// ===== portable jthread-like wrapper =========================================
34// If real std::jthread is present, use it. Otherwise, define a minimal shim
35// that joins in the destructor (no stop_token support, but good enough here).
36#if defined(__cpp_lib_jthread) // header exists
37#include <jthread>
38using jthread_alias = std::jthread;
39#else
40// join: pause right here until that thread is finished.
41class jthread_alias : public std::thread {
42public:
43 using std::thread::thread; // inherit all ctors
44 ~jthread_alias() { if (joinable()) join(); }
45 jthread_alias(jthread_alias&&) noexcept = default;
46 jthread_alias& operator=(jthread_alias&&) noexcept = default;
47 // no copy
48 jthread_alias(const jthread_alias&) = delete;
49 jthread_alias& operator=(const jthread_alias&) = delete;
50};
51#endif
52
54 int nthreads,
55 const std::shared_ptr<GOptions>& gopt,
56 const std::shared_ptr<GLogger>& log) -> std::vector<std::shared_ptr<GEventDataCollection>> {
57 std::mutex collectorMtx;
58 std::vector<std::shared_ptr<GEventDataCollection>> collected;
59
60 // thread-safe integer counter starts at 1.
61 // fetch_add returns the old value *and* bumps.
62 // zero contention: each thread fetches the next free event number.
63 std::atomic<int> next{1};
64
65 // pool of jthreads. jthread joins in its destructor so we don’t need an
66 // explicit loop at the end.
67 // each element represents one worker thread running your event-processing lambda.
68 // std::vector<std::jthread> pool; use this when C++20 is widely available
69 std::vector<jthread_alias> pool; // was std::vector<std::jthread>
70
71 pool.reserve(nthreads);
72
73 for (int tid = 0; tid < nthreads; ++tid) {
74 // The capture [&, tid] gives the thread references to variables like next, nevents, runDataMtx, etc.
75 pool.emplace_back([&, tid] // capture tid *by value*
76 {
77 // start the thread with a lambda
78 log->info(0, "worker ", tid, " started");
79
80 int localCount = 0; // events built by *this* worker
81 thread_local std::vector<std::shared_ptr<GEventDataCollection>> localRunData;
82
83 while (true) {
84 // repeatedly asks the shared atomic counter for “the next unclaimed event
85 // number,” processes that event, stores the result, and goes back for more.
86 // memory_order_relaxed: we only need *atomicity*, no ordering
87 int evn = next.fetch_add(1, std::memory_order_relaxed); // atomically returns the current value and increments it by 1.
88 if (evn > nevents) break; // exit the while loop
89
90 auto event_data_collection = GEventDataCollection::create(gopt);
91 localRunData.emplace_back(event_data_collection);
92
93 ++localCount; // tally for this worker
94 }
95
96 // braces to lock the mutex when it's constructed and unlocks when it is destroyed
97 {
98 std::scoped_lock lk(collectorMtx);
99 for (auto& evt : localRunData) { collected.emplace_back(evt); }
100 localRunData.clear();
101 }
102
103 log->info(0, "worker ", tid, " processed ", localCount, " events");
104 }); // jthread constructor launches the thread immediately
105 } // pool’s destructor blocks until every jthread has joined
106 return collected;
107}
108
109
110// emulation of a run of events, collecting data in separate threads
111
112int main(int argc, char* argv[]) {
113 // Create GOptions using gevent_data::defineOptions, which aggregates options from all gdata and gtouchable.
114 auto gopts = std::make_shared<GOptions>(argc, argv, gevent_data::defineOptions());
115
116 // Create loggers: one for gdata and one for gtouchable.
117 auto log = std::make_shared<GLogger>(gopts, SFUNCTION_NAME, GEVENTDATA_LOGGER);
118
119 constexpr int nevents = 10;
120 constexpr int nthreads = 8;
121
122 auto runData = run_simulation_in_threads(nevents, nthreads, gopts, log);
123
124 // For demonstration, we'll simply print the event numbers.
125 for (size_t i = 0; i < runData.size(); i++) { log->info("event n. ", i + 1, " collected with local event number: ", runData[i]->getEventNumber()); }
126
127 return EXIT_SUCCESS;
128}
static std::shared_ptr< GEventDataCollection > create(const std::shared_ptr< GOptions > &gopts)
jthread_alias(jthread_alias &&) noexcept=default
constexpr const char * GEVENTDATA_LOGGER
int main(int argc, char *argv[])
auto run_simulation_in_threads(int nevents, int nthreads, const std::shared_ptr< GOptions > &gopt, const std::shared_ptr< GLogger > &log) -> std::vector< std::shared_ptr< GEventDataCollection > >
GOptions defineOptions()