Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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
81using G4Mutex = std::mutex;
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 auto* _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
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