ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4MTBarrier.hh
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4MTBarrier.hh
1 //
2 // ********************************************************************
3 // * License and Disclaimer *
4 // * *
5 // * The Geant4 software is copyright of the Copyright Holders of *
6 // * the Geant4 Collaboration. It is provided under the terms and *
7 // * conditions of the Geant4 Software License, included in the file *
8 // * LICENSE and available at http://cern.ch/geant4/license . These *
9 // * include a list of copyright holders. *
10 // * *
11 // * Neither the authors of this software system, nor their employing *
12 // * institutes,nor the agencies providing financial support for this *
13 // * work make any representation or warranty, express or implied, *
14 // * regarding this software system or assume any liability for its *
15 // * use. Please see the license in the file LICENSE and URL above *
16 // * for the full disclaimer and the limitation of liability. *
17 // * *
18 // * This code implementation is the result of the scientific and *
19 // * technical work of the GEANT4 collaboration. *
20 // * By using, copying, modifying or distributing the software (or *
21 // * any work based on the software) you agree to acknowledge its *
22 // * use in resulting scientific publications, and indicate your *
23 // * acceptance of all terms of the Geant4 Software license. *
24 // ********************************************************************
25 //
26 //
27 // ---------------------------------------------------------------
28 // GEANT 4 class header file
29 //
30 // Class Description:
31 //
32 // This class defines a synchronization point between threads: a master
33 // and a pool of workers.
34 // A barrier is a (shared) instance of this class. Master sets the number
35 // of active threads to wait for, then it waits for workers to become ready
36 // calling the method WaitForReadyWorkers(). The master thread will block on this
37 // call.
38 // Each of the workers calls ThisWorkerReady() when it is ready to continue.
39 // It will block on this call.
40 // When all worker threads have called ThisWorkerReady and are waiting the
41 // master will release the barrier and execution will continue.
42 //
43 // User code can implement more advanced barriers that require exchange
44 // of a message between master and threads inheriting from this class as in:
45 // class Derived : public G4MTBarrier {
46 // G4Mutex mutexForMessage;
47 // SomeType message;
48 // void MethodCalledByWorkers() {
49 // G4MTBarrirer::ThisWorkerReady();
50 // G4AutoLock l(&mutexForMessage);
51 // [... process message ...]
52 // }
53 // void WaitForReadyWorkers() override {
54 // Wait(); <== Mandatory
55 // [.. process message ...] <== User code between the two calls
56 // ReleaseBarrier(); <== Mandatory
57 // }
58 // void MethodCalledByMaster() { WaitForReadyWorkers(); }
59 // }
60 // User code can also achieve the same results as before using the granular
61 // methods LoopWaitingWorkers and ResetCounterAndBroadcast methods in the
62 // master. For examples of usage of this class see G4MTRunManager
63 //
64 // G4MTBarrier.hh
65 //
66 // Created on: Feb 10, 2016
67 // Author: adotti
68 //
69 // =====================================
70 // Barriers mechanism
71 // =====================================
72 // We want to implement barriers.
73 // We define a barrier has a point in which threads synchronize.
74 // When workers threads reach a barrier they wait for the master thread a
75 // signal that they can continue. The master thread broadcast this signal
76 // only when all worker threads have reached this point.
77 // Currently only three points require this sync in the life-time of a G4 applicattion:
78 // Just before and just after the for-loop controlling the thread event-loop.
79 // Between runs.
80 //
81 // The basic algorithm of each barrier works like this:
82 // In the master:
83 // WaitWorkers() {
84 // while (true)
85 // {
86 // G4AutoLock l(&counterMutex); || Mutex is locked (1)
87 // if ( counter == nActiveThreads ) break;
88 // G4CONDITIONWAIT( &conditionOnCounter, &counterMutex); || Mutex is atomically released and wait, upon return locked (2)
89 // } || unlock mutex
90 // G4AutoLock l(&counterMutex); || lock again mutex (3)
91 // G4CONDITIONBROADCAST( &doSomethingCanStart ); || Here mutex is locked (4)
92 // } || final unlock (5)
93 // In the workers:
94 // WaitSignalFromMaster() {
95 // G4AutoLock l(&counterMutex); || (6)
96 // ++counter;
97 // G4CONDITIONBROADCAST(&conditionOnCounter); || (7)
98 // G4CONDITIONWAIT( &doSomethingCanStart , &counterMutex);|| (8)
99 // }
100 // Each barriers requires 2 conditions and one mutex, plus a counter.
101 // Important note: the thread calling broadcast should hold the mutex
102 // before calling broadcast to obtain predictible behavior
103 // http://pubs.opengroup.org/onlinepubs/7908799/xsh/pthread_cond_broadcast.html
104 // Also remember that the wait for condition will atomically release the mutex
105 // and wait on condition, but it will lock again on mutex when returning
106 // Here it is how the control flows.
107 // Imagine master starts and only one worker (nActiveThreads==1)
108 // Master | Worker | counter | Who holds mutex
109 // Gets to (1) | Blocks on (6) | 0 | M
110 // Waits in (2) | | 0 | -
111 // | Arrives to (7) | 1 | W
112 // | Waits in (8) | 1 | -
113 // Gets to (1) | | 1 | M
114 // Jumps to (3) | | 1 | M
115 // End | | 1 | -
116 // | End | 1 | -
117 // Similarly for more than one worker threads or if worker starts
118 
119 #ifndef G4MTBARRIER_HH_
120 #define G4MTBARRIER_HH_
121 
122 #include "G4Threading.hh"
123 
125 {
126 public:
128  virtual ~G4MTBarrier() {}
129  G4MTBarrier(const G4MTBarrier&) = delete;
130  G4MTBarrier& operator=(const G4MTBarrier&) = delete;
131  //on explicitly defaulted move at
132  //https://msdn.microsoft.com/en-us/library/dn457344.aspx
133  //G4MTBarrier(G4MTBarrier&&) = default;
134  //G4MTBarrier& operator=(G4MTBarrier&&) = default;
135  G4MTBarrier( unsigned int numThreads );
136  void ThisWorkerReady();
137  virtual void WaitForReadyWorkers();
138  inline void SetActiveThreads( unsigned int val ) { m_numActiveThreads = val; }
139  void ResetCounter();
140  unsigned int GetCounter();
141  void Wait();
142  void ReleaseBarrier();
143  inline void Wait( unsigned int numt ) {
144  SetActiveThreads( numt );
145  Wait();
146  }
147 private:
148  unsigned int m_numActiveThreads;
149  unsigned int m_counter;
153 };
154 
155 #endif /* G4MTBARRIER_HH_ */