Geant4-11
G4Threading.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// G4Threading
27//
28// Description:
29//
30// This unit defines types and macros used to expose Geant4 threading model.
31
32// Author: Andrea Dotti, 15 February 2013 - First Implementation
33// Revision: Jonathan R. Madsen, 21 February 2018
34// --------------------------------------------------------------------
35#ifndef G4Threading_hh
36#define G4Threading_hh 1
37
38#include "G4Types.hh"
39#include "globals.hh"
40
41#include <chrono>
42#include <condition_variable>
43#include <future>
44#include <mutex>
45#include <thread>
46#include <vector>
47
48// Macro to put current thread to sleep
49//
50#define G4THREADSLEEP(tick) \
51 std::this_thread::sleep_for(std::chrono::seconds(tick))
52
53// Will be used in the future when migrating threading to task-based style
54template <typename _Tp>
55using G4Future = std::future<_Tp>;
56template <typename _Tp>
57using G4SharedFuture = std::shared_future<_Tp>;
58template <typename _Tp>
59using G4Promise = std::promise<_Tp>;
60
61// NOTE ON GEANT4 SERIAL BUILDS AND MUTEX/UNIQUE_LOCK
62// ==================================================
63//
64// G4Mutex and G4RecursiveMutex are always C++11 std::mutex types
65// however, in serial mode, using G4MUTEXLOCK and G4MUTEXUNLOCK on these
66// types has no effect -- i.e. the mutexes are not actually locked or unlocked
67//
68// Additionally, when a G4Mutex or G4RecursiveMutex is used with G4AutoLock
69// and G4RecursiveAutoLock, respectively, these classes also suppressing
70// the locking and unlocking of the mutex. Regardless of the build type,
71// G4AutoLock and G4RecursiveAutoLock inherit from std::unique_lock<std::mutex>
72// and std::unique_lock<std::recursive_mutex>, respectively. This means
73// that in situations (such as is needed by the analysis category), the
74// G4AutoLock and G4RecursiveAutoLock can be passed to functions requesting
75// a std::unique_lock. Within these functions, since std::unique_lock
76// member functions are not virtual, they will not retain the dummy locking
77// and unlocking behavior
78// --> An example of this behavior can be found in G4AutoLock.hh
79
80// Global mutex types
82using G4RecursiveMutex = std::recursive_mutex;
83
84// Mutex macros
85#define G4MUTEX_INITIALIZER \
86 {}
87#define G4MUTEXINIT(mutex) \
88 ; \
89 ;
90#define G4MUTEXDESTROY(mutex) \
91 ; \
92 ;
93
94// Static functions: get_id(), sleep_for(...), sleep_until(...), yield(),
95namespace G4ThisThread
96{
97 using namespace std::this_thread;
98}
99
100// Will be used in the future when migrating threading to task-based style
101// and are currently used in unit tests
102template <typename _Tp>
103using G4Promise = std::promise<_Tp>;
104template <typename _Tp>
105using G4Future = std::future<_Tp>;
106template <typename _Tp>
107using G4SharedFuture = std::shared_future<_Tp>;
108
109// Some useful types
111using G4ThreadFunArgType = void*;
113 G4int (*)(G4Mutex*); // typedef G4int (*thread_lock)(G4Mutex*);
115 G4int (*)(G4Mutex*); // typedef G4int (*thread_unlock)(G4Mutex*);
116
117// Helper function for getting a unique static mutex for a specific
118// class or type
119// Usage example:
120// a template class "G4Cache<T>" that required a static
121// mutex for specific to type T:
122// G4AutoLock l(G4TypeMutex<G4Cache<T>>());
123template <typename _Tp>
124G4Mutex& G4TypeMutex(const unsigned int& _n = 0)
125{
126 static G4Mutex* _mutex = new G4Mutex();
127 if(_n == 0)
128 return *_mutex;
129
130 static std::vector<G4Mutex*> _mutexes;
131 if(_n > _mutexes.size())
132 _mutexes.resize(_n, nullptr);
133 if(!_mutexes[_n])
134 _mutexes[_n] = new G4Mutex();
135 return *(_mutexes[_n - 1]);
136}
137
138// Helper function for getting a unique static recursive_mutex for a
139// specific class or type
140// Usage example:
141// a template class "G4Cache<T>" that required a static
142// recursive_mutex for specific to type T:
143// G4RecursiveAutoLock
144// l(G4TypeRecursiveMutex<G4Cache<T>>());
145template <typename _Tp>
146G4RecursiveMutex& G4TypeRecursiveMutex(const unsigned int& _n = 0)
147{
148 static G4RecursiveMutex* _mutex = new G4RecursiveMutex();
149 if(_n == 0)
150 return *(_mutex);
151
152 static std::vector<G4RecursiveMutex*> _mutexes;
153 if(_n > _mutexes.size())
154 _mutexes.resize(_n, nullptr);
155 if(!_mutexes[_n])
156 _mutexes[_n] = new G4RecursiveMutex();
157 return *(_mutexes[_n - 1]);
158}
159
160#if defined(G4MULTITHREADED)
161//==========================================
162// G4MULTITHREADED is ON - threading enabled
163//==========================================
164
165// global thread types
166using G4Thread = std::thread;
167using G4NativeThread = std::thread::native_handle_type;
168
169// mutex macros
170# define G4MUTEXLOCK(mutex) \
171 { \
172 (mutex)->lock(); \
173 }
174# define G4MUTEXUNLOCK(mutex) \
175 { \
176 (mutex)->unlock(); \
177 }
178
179// Macro to join thread
180# define G4THREADJOIN(worker) (worker).join()
181
182// std::thread::id does not cast to integer
183using G4Pid_t = std::thread::id;
184
185// Instead of previous macro taking one argument, define function taking
186// unlimited arguments
187template <typename _Worker, typename _Func, typename... _Args>
188void G4THREADCREATE(_Worker*& worker, _Func func, _Args... args)
189{
190 *worker = G4Thread(func, std::forward<_Args>(args)...);
191}
192
193// Conditions
194//
195// See G4MTRunManager for example on how to use these
196//
197using G4Condition = std::condition_variable;
198# define G4CONDITION_INITIALIZER \
199 {}
200# define G4CONDITIONWAIT(cond, lock) (cond)->wait(*lock);
201# define G4CONDITIONWAITLAMBDA(cond, lock, lambda) (cond)->wait(*lock, lambda);
202# define G4CONDITIONNOTIFY(cond) (cond)->notify_one();
203# define G4CONDITIONBROADCAST(cond) (cond)->notify_all();
204//
205// we don't define above globally so single-threaded code does not get
206// caught in condition with no other thread to wake it up
207//
208
209#else
210//==========================================
211// G4MULTITHREADED is OFF - Sequential build
212//==========================================
213
214// implement a dummy thread class that acts like a thread
216{
217 public:
219 using id = std::thread::id;
220
221 public:
222 // does nothing
224 // a std::thread-like constructor that execute upon construction
225 template <typename _Func, typename... _Args>
226 G4DummyThread(_Func func, _Args&&... _args)
227 {
228 func(std::forward<_Args>(_args)...);
229 }
230
231 public:
233 G4bool joinable() const { return true; }
234 id get_id() const noexcept { return std::this_thread::get_id(); }
236 void join() {}
237 void detach() {}
238
239 public:
240 static unsigned int hardware_concurrency() noexcept
241 {
242 return std::thread::hardware_concurrency();
243 }
244};
245
246// global thread types
249
250// mutex macros
251# define G4MUTEXLOCK(mutex) \
252 ; \
253 ;
254# define G4MUTEXUNLOCK(mutex) \
255 ; \
256 ;
257
258// Macro to join thread
259# define G4THREADJOIN(worker) \
260 ; \
261 ;
262
264
265// Instead of previous macro taking one argument, define function taking
266// unlimited arguments
267template <typename _Worker, typename _Func, typename... _Args>
268void G4THREADCREATE(_Worker*& worker, _Func func, _Args... args)
269{
270 *worker = G4Thread(func, std::forward<_Args>(args)...);
271}
272
274# define G4CONDITION_INITIALIZER 1
275# define G4CONDITIONWAIT(cond, mutex) G4ConsumeParameters(cond, mutex);
276# define G4CONDITIONWAITLAMBDA(cond, mutex, lambda) \
277 G4ConsumeParameters(cond, mutex, lambda);
278# define G4CONDITIONNOTIFY(cond) G4ConsumeParameters(cond);
279# define G4CONDITIONBROADCAST(cond) G4ConsumeParameters(cond);
280
281#endif // G4MULTITHREADING
282
283//============================================================================//
284
285// Define here after G4Thread has been typedef
287
288//============================================================================//
289
290namespace G4Threading
291{
292 enum
293 {
297 GENERICTHREAD_ID = -1000
298 };
299
305 void G4SetThreadId(G4int aNewValue);
312} // namespace G4Threading
313
314#endif // G4Threading_hh
std::future< _Tp > G4Future
Definition: G4Threading.hh:55
G4RecursiveMutex & G4TypeRecursiveMutex(const unsigned int &_n=0)
Definition: G4Threading.hh:146
G4Thread::id G4ThreadId
Definition: G4Threading.hh:286
G4int(*)(G4Mutex *) thread_unlock
Definition: G4Threading.hh:115
G4int G4Pid_t
Definition: G4Threading.hh:263
G4int G4Condition
Definition: G4Threading.hh:273
void G4THREADCREATE(_Worker *&worker, _Func func, _Args... args)
Definition: G4Threading.hh:268
std::recursive_mutex G4RecursiveMutex
Definition: G4Threading.hh:82
std::shared_future< _Tp > G4SharedFuture
Definition: G4Threading.hh:57
G4DummyThread G4Thread
Definition: G4Threading.hh:247
G4Mutex & G4TypeMutex(const unsigned int &_n=0)
Definition: G4Threading.hh:124
G4DummyThread::native_handle_type G4NativeThread
Definition: G4Threading.hh:248
std::promise< _Tp > G4Promise
Definition: G4Threading.hh:59
void * G4ThreadFunReturnType
Definition: G4Threading.hh:110
G4int(*)(G4Mutex *) thread_lock
Definition: G4Threading.hh:113
void * G4ThreadFunArgType
Definition: G4Threading.hh:111
std::mutex G4Mutex
Definition: G4Threading.hh:81
bool G4bool
Definition: G4Types.hh:86
int G4int
Definition: G4Types.hh:85
static char ** args
Definition: G4Xt.cc:51
G4DummyThread(_Func func, _Args &&... _args)
Definition: G4Threading.hh:226
G4bool joinable() const
Definition: G4Threading.hh:233
static unsigned int hardware_concurrency() noexcept
Definition: G4Threading.hh:240
G4int native_handle_type
Definition: G4Threading.hh:218
void swap(G4DummyThread &)
Definition: G4Threading.hh:235
id get_id() const noexcept
Definition: G4Threading.hh:234
std::thread::id id
Definition: G4Threading.hh:219
native_handle_type native_handle() const
Definition: G4Threading.hh:232
G4int WorkerThreadJoinsPool()
Definition: G4Threading.cc:132
G4bool G4SetPinAffinity(G4int idx, G4NativeThread &at)
Definition: G4Threading.cc:127
G4int G4GetNumberOfCores()
Definition: G4Threading.cc:121
G4int WorkerThreadLeavesPool()
Definition: G4Threading.cc:131
G4bool IsWorkerThread()
Definition: G4Threading.cc:123
G4bool IsMultithreadedApplication()
Definition: G4Threading.cc:130
G4Pid_t G4GetPidId()
Definition: G4Threading.cc:111
G4bool IsMasterThread()
Definition: G4Threading.cc:124
G4int G4GetThreadId()
Definition: G4Threading.cc:122
void SetMultithreadedApplication(G4bool value)
Definition: G4Threading.cc:129
G4int GetNumberOfRunningWorkerThreads()
Definition: G4Threading.cc:133
void G4SetThreadId(G4int aNewValue)
Definition: G4Threading.cc:125