Geant4-11
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// 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
123{
124 public:
126 : G4MTBarrier(1)
127 {}
128 virtual ~G4MTBarrier() {}
129 G4MTBarrier(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;
157};
158
159#endif
G4int G4Condition
Definition: G4Threading.hh:273
std::mutex G4Mutex
Definition: G4Threading.hh:81
unsigned int m_counter
Definition: G4MTBarrier.hh:153
G4Mutex m_mutex
Definition: G4MTBarrier.hh:154
void Wait(unsigned int numt)
Definition: G4MTBarrier.hh:145
void ThisWorkerReady()
Definition: G4MTBarrier.cc:40
G4Condition m_counterChanged
Definition: G4MTBarrier.hh:155
virtual ~G4MTBarrier()
Definition: G4MTBarrier.hh:128
void ResetCounter()
Definition: G4MTBarrier.cc:90
G4Condition m_continue
Definition: G4MTBarrier.hh:156
G4MTBarrier(const G4MTBarrier &)=delete
void Wait()
Definition: G4MTBarrier.cc:53
virtual void WaitForReadyWorkers()
Definition: G4MTBarrier.cc:81
void ReleaseBarrier()
Definition: G4MTBarrier.cc:72
unsigned int m_numActiveThreads
Definition: G4MTBarrier.hh:152
void SetActiveThreads(unsigned int val)
Definition: G4MTBarrier.hh:140
G4MTBarrier & operator=(const G4MTBarrier &)=delete
unsigned int GetCounter()
Definition: G4MTBarrier.cc:97