Geant4  10.03.p01
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
G4MTBarrier.hh
Go to the documentation of this file.
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 // $Id$
27 //
28 // ---------------------------------------------------------------
29 // GEANT 4 class header file
30 //
31 // Class Description:
32 //
33 // This class defines a synchronization point between threads: a master
34 // and a pool of workers.
35 // A barrier is a (shared) instance of this class. Master sets the number
36 // of active threads to wait for, then it waits for workers to become ready
37 // calling the method WaitForReadyWorkers(). The master thread will block on this
38 // call.
39 // Each of the workers calls ThisWorkerReady() when it is ready to continue.
40 // It will block on this call.
41 // When all worker threads have called ThisWorkerReady and are waiting the
42 // master will release the barrier and execution will continue.
43 //
44 // User code can implement more advanced barriers that require exchange
45 // of a message between master and threads inheriting from this class as in:
46 // class Derived : public G4MTBarrier {
47 // G4Mutex mutexForMessage;
48 // SomeType message;
49 // void MethodCalledByWorkers() {
50 // G4MTBarrirer::ThisWorkerReady();
51 // G4AutoLock l(&mutexForMessage);
52 // [... process message ...]
53 // }
54 // void WaitForReadyWorkers() override {
55 // Wait(); <== Mandatory
56 // [.. process message ...] <== User code between the two calls
57 // ReleaseBarrier(); <== Mandatory
58 // }
59 // void MethodCalledByMaster() { WaitForReadyWorkers(); }
60 // }
61 // User code can also achieve the same results as before using the granular
62 // methods LoopWaitingWorkers and ResetCounterAndBroadcast methods in the
63 // master. For examples of usage of this class see G4MTRunManager
64 //
65 // G4MTBarrier.hh
66 //
67 // Created on: Feb 10, 2016
68 // Author: adotti
69 //
70 // =====================================
71 // Barriers mechanism
72 // =====================================
73 // We want to implement barriers.
74 // We define a barrier has a point in which threads synchronize.
75 // When workers threads reach a barrier they wait for the master thread a
76 // signal that they can continue. The master thread broadcast this signal
77 // only when all worker threads have reached this point.
78 // Currently only three points require this sync in the life-time of a G4 applicattion:
79 // Just before and just after the for-loop controlling the thread event-loop.
80 // Between runs.
81 //
82 // The basic algorithm of each barrier works like this:
83 // In the master:
84 // WaitWorkers() {
85 // while (true)
86 // {
87 // G4AutoLock l(&counterMutex); || Mutex is locked (1)
88 // if ( counter == nActiveThreads ) break;
89 // G4CONDITIONWAIT( &conditionOnCounter, &counterMutex); || Mutex is atomically released and wait, upon return locked (2)
90 // } || unlock mutex
91 // G4AutoLock l(&counterMutex); || lock again mutex (3)
92 // G4CONDITIONBROADCAST( &doSomethingCanStart ); || Here mutex is locked (4)
93 // } || final unlock (5)
94 // In the workers:
95 // WaitSignalFromMaster() {
96 // G4AutoLock l(&counterMutex); || (6)
97 // ++counter;
98 // G4CONDITIONBROADCAST(&conditionOnCounter); || (7)
99 // G4CONDITIONWAIT( &doSomethingCanStart , &counterMutex);|| (8)
100 // }
101 // Each barriers requires 2 conditions and one mutex, plus a counter.
102 // Important note: the thread calling broadcast should hold the mutex
103 // before calling broadcast to obtain predictible behavior
104 // http://pubs.opengroup.org/onlinepubs/7908799/xsh/pthread_cond_broadcast.html
105 // Also remember that the wait for condition will atomically release the mutex
106 // and wait on condition, but it will lock again on mutex when returning
107 // Here it is how the control flows.
108 // Imagine master starts and only one worker (nActiveThreads==1)
109 // Master | Worker | counter | Who holds mutex
110 // Gets to (1) | Blocks on (6) | 0 | M
111 // Waits in (2) | | 0 | -
112 // | Arrives to (7) | 1 | W
113 // | Waits in (8) | 1 | -
114 // Gets to (1) | | 1 | M
115 // Jumps to (3) | | 1 | M
116 // End | | 1 | -
117 // | End | 1 | -
118 // Similarly for more than one worker threads or if worker starts
119 
120 #ifndef G4MTBARRIER_HH_
121 #define G4MTBARRIER_HH_
122 #include "G4Threading.hh"
123 
124 #ifdef WIN32
125 #include "windefs.hh"
126 #endif
127 
129 {
130 public:
132  virtual ~G4MTBarrier() {}
133  G4MTBarrier(const G4MTBarrier&) = delete;
134  G4MTBarrier& operator=(const G4MTBarrier&) = delete;
135  //on explicitly defaulted move at
136  //https://msdn.microsoft.com/en-us/library/dn457344.aspx
137  //G4MTBarrier(G4MTBarrier&&) = default;
138  //G4MTBarrier& operator=(G4MTBarrier&&) = default;
139  G4MTBarrier( unsigned int numThreads );
140  void ThisWorkerReady();
141  virtual void WaitForReadyWorkers();
142  inline void SetActiveThreads( unsigned int val ) { m_numActiveThreads = val; }
143  void ResetCounter();
144  unsigned int GetCounter();
145  void Wait();
146  void ReleaseBarrier();
147  inline void Wait( unsigned int numt ) {
148  SetActiveThreads( numt );
149  Wait();
150  }
151 private:
152  unsigned int m_numActiveThreads;
153  unsigned int m_counter;
154  G4Mutex m_mutex;
155  G4Condition m_counterChanged;
156  G4Condition m_continue;
157 #if defined(WIN32)
158  CRITICAL_SECTION cs1;
159  CRITICAL_SECTION cs2;
160 #endif
161 
162 };
163 
164 #endif /* G4MTBARRIER_HH_ */
void SetActiveThreads(unsigned int val)
Definition: G4MTBarrier.hh:142
virtual void WaitForReadyWorkers()
Definition: G4MTBarrier.cc:104
void Wait(unsigned int numt)
Definition: G4MTBarrier.hh:147
void ThisWorkerReady()
Definition: G4MTBarrier.cc:51
void ResetCounter()
Definition: G4MTBarrier.cc:111
unsigned int GetCounter()
Definition: G4MTBarrier.cc:116
void ReleaseBarrier()
Definition: G4MTBarrier.cc:97
G4int G4Mutex
Definition: G4Threading.hh:173
G4MTBarrier & operator=(const G4MTBarrier &)=delete
void Wait()
Definition: G4MTBarrier.cc:73
virtual ~G4MTBarrier()
Definition: G4MTBarrier.hh:132
G4int G4Condition
Definition: G4Threading.hh:189