Geant4 11.3.0
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>
125{
126 static G4Mutex _mutex;
127 return _mutex;
128}
129
130// Helper function for getting a unique static recursive_mutex for a
131// specific class or type
132// Usage example:
133// a template class "G4Cache<T>" that required a static
134// recursive_mutex for specific to type T:
135// G4RecursiveAutoLock
136// l(G4TypeRecursiveMutex<G4Cache<T>>());
137template <typename _Tp>
139{
140 static G4RecursiveMutex _mutex;
141 return _mutex;
142}
143
144#if defined(G4MULTITHREADED)
145//==========================================
146// G4MULTITHREADED is ON - threading enabled
147//==========================================
148
149// global thread types
150using G4Thread = std::thread;
151using G4NativeThread = std::thread::native_handle_type;
152
153// mutex macros
154# define G4MUTEXLOCK(mutex) \
155 { \
156 (mutex)->lock(); \
157 }
158# define G4MUTEXUNLOCK(mutex) \
159 { \
160 (mutex)->unlock(); \
161 }
162
163// Macro to join thread
164# define G4THREADJOIN(worker) (worker).join()
165
166// std::thread::id does not cast to integer
167using G4Pid_t = std::thread::id;
168
169// Instead of previous macro taking one argument, define function taking
170// unlimited arguments
171template <typename _Worker, typename _Func, typename... _Args>
172void G4THREADCREATE(_Worker*& worker, _Func func, _Args... args)
173{
174 *worker = G4Thread(func, std::forward<_Args>(args)...);
175}
176
177// Conditions
178//
179// See G4MTRunManager for example on how to use these
180//
181using G4Condition = std::condition_variable;
182# define G4CONDITION_INITIALIZER \
183 {}
184# define G4CONDITIONWAIT(cond, lock) (cond)->wait(*lock);
185# define G4CONDITIONWAITLAMBDA(cond, lock, lambda) (cond)->wait(*lock, lambda);
186# define G4CONDITIONNOTIFY(cond) (cond)->notify_one();
187# define G4CONDITIONBROADCAST(cond) (cond)->notify_all();
188//
189// we don't define above globally so single-threaded code does not get
190// caught in condition with no other thread to wake it up
191//
192
193#else
194//==========================================
195// G4MULTITHREADED is OFF - Sequential build
196//==========================================
197
198// implement a dummy thread class that acts like a thread
200{
201 public:
203 using id = std::thread::id;
204
205 public:
206 // does nothing
208 // a std::thread-like constructor that execute upon construction
209 template <typename _Func, typename... _Args>
210 G4DummyThread(_Func func, _Args&&... _args)
211 {
212 func(std::forward<_Args>(_args)...);
213 }
214
215 public:
217 G4bool joinable() const { return true; }
218 id get_id() const noexcept { return std::this_thread::get_id(); }
220 void join() {}
221 void detach() {}
222
223 public:
224 static unsigned int hardware_concurrency() noexcept
225 {
226 return std::thread::hardware_concurrency();
227 }
228};
229
230// global thread types
233
234// mutex macros
235# define G4MUTEXLOCK(mutex) \
236 ; \
237 ;
238# define G4MUTEXUNLOCK(mutex) \
239 ; \
240 ;
241
242// Macro to join thread
243# define G4THREADJOIN(worker) \
244 ; \
245 ;
246
248
249// Instead of previous macro taking one argument, define function taking
250// unlimited arguments
251template <typename _Worker, typename _Func, typename... _Args>
252void G4THREADCREATE(_Worker*& worker, _Func func, _Args... args)
253{
254 *worker = G4Thread(func, std::forward<_Args>(args)...);
255}
256
258# define G4CONDITION_INITIALIZER 1
259# define G4CONDITIONWAIT(cond, mutex) G4ConsumeParameters(cond, mutex);
260# define G4CONDITIONWAITLAMBDA(cond, mutex, lambda) \
261 G4ConsumeParameters(cond, mutex, lambda);
262# define G4CONDITIONNOTIFY(cond) G4ConsumeParameters(cond);
263# define G4CONDITIONBROADCAST(cond) G4ConsumeParameters(cond);
264
265#endif // G4MULTITHREADING
266
267//============================================================================//
268
269// Define here after G4Thread has been typedef
271
272//============================================================================//
273
297
298#endif // G4Threading_hh
std::future< _Tp > G4Future
G4int(*)(G4Mutex *) thread_unlock
G4Thread::id G4ThreadId
G4int G4Pid_t
G4int G4Condition
void G4THREADCREATE(_Worker *&worker, _Func func, _Args... args)
G4RecursiveMutex & G4TypeRecursiveMutex()
std::recursive_mutex G4RecursiveMutex
std::shared_future< _Tp > G4SharedFuture
G4DummyThread G4Thread
G4DummyThread::native_handle_type G4NativeThread
std::promise< _Tp > G4Promise
void * G4ThreadFunReturnType
void * G4ThreadFunArgType
G4Mutex & G4TypeMutex()
std::mutex G4Mutex
G4int(*)(G4Mutex *) thread_lock
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
G4DummyThread(_Func func, _Args &&... _args)
G4bool joinable() const
static unsigned int hardware_concurrency() noexcept
G4int native_handle_type
void swap(G4DummyThread &)
id get_id() const noexcept
std::thread::id id
native_handle_type native_handle() const
G4int WorkerThreadJoinsPool()
G4bool G4SetPinAffinity(G4int idx, G4NativeThread &at)
G4int G4GetNumberOfCores()
G4int WorkerThreadLeavesPool()
G4bool IsWorkerThread()
G4bool IsMultithreadedApplication()
G4Pid_t G4GetPidId()
G4bool IsMasterThread()
G4int G4GetThreadId()
void SetMultithreadedApplication(G4bool value)
G4int GetNumberOfRunningWorkerThreads()
void G4SetThreadId(G4int aNewValue)