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