Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/global/management/include/G4AutoLock.hh

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

Diff markup

Differences between /global/management/include/G4AutoLock.hh (Version 11.3.0) and /global/management/include/G4AutoLock.hh (Version 2.0)


  1 //                                                  1 
  2 // *******************************************    
  3 // * License and Disclaimer                       
  4 // *                                              
  5 // * The  Geant4 software  is  copyright of th    
  6 // * the Geant4 Collaboration.  It is provided    
  7 // * conditions of the Geant4 Software License    
  8 // * LICENSE and available at  http://cern.ch/    
  9 // * include a list of copyright holders.         
 10 // *                                              
 11 // * Neither the authors of this software syst    
 12 // * institutes,nor the agencies providing fin    
 13 // * work  make  any representation or  warran    
 14 // * regarding  this  software system or assum    
 15 // * use.  Please see the license in the file     
 16 // * for the full disclaimer and the limitatio    
 17 // *                                              
 18 // * This  code  implementation is the result     
 19 // * technical work of the GEANT4 collaboratio    
 20 // * By using,  copying,  modifying or  distri    
 21 // * any work based  on the software)  you  ag    
 22 // * use  in  resulting  scientific  publicati    
 23 // * acceptance of all terms of the Geant4 Sof    
 24 // *******************************************    
 25 //                                                
 26 // G4Autolock                                     
 27 //                                                
 28 // Class Description:                             
 29 //                                                
 30 // This class provides a mechanism to create a    
 31 // Can be used by applications to implement in    
 32 // Usage Example:                                 
 33 //                                                
 34 //      #include "G4Threading.hh"                 
 35 //      #include "G4AutoLock.hh"                  
 36 //                                                
 37 //      // defined somewhere -- static so all     
 38 //      static G4Mutex aMutex;                    
 39 //                                                
 40 //      // somewhere else:                        
 41 //      // The G4AutoLock instance will automa    
 42 //      // goes out of scope. One typically de    
 43 //      // there is thread-safe code following    
 44 //                                                
 45 //      {                                         
 46 //          G4AutoLock l(&aMutex);                
 47 //          ProtectedCode();                      
 48 //      }                                         
 49 //                                                
 50 //      UnprotectedCode();                        
 51 //                                                
 52 //      // When ProtectedCode() is calling a f    
 53 //      // a normal G4AutoLock + G4Mutex will     
 54 //      // the mutex in the ProtectedCode() fu    
 55 //      // acquire the lock that is being held    
 56 //      // ProtectedCode(). In this situation,    
 57 //      // G4RecursiveMutex, e.g.                 
 58 //                                                
 59 //      // defined somewhere -- static so all     
 60 //      static G4RecursiveMutex aRecursiveMute    
 61 //                                                
 62 //      // this function is sometimes called d    
 63 //      // from SomeFunction_B(), which also l    
 64 //      void SomeFunction_A()                     
 65 //      {                                         
 66 //          // when called from SomeFunction_B    
 67 //          // deadlock                           
 68 //          G4RecursiveAutoLock l(&aRecursiveM    
 69 //          // do something                       
 70 //      }                                         
 71 //                                                
 72 //      void SomeFunction_B()                     
 73 //      {                                         
 74 //                                                
 75 //          {                                     
 76 //              G4RecursiveAutoLock l(&aRecurs    
 77 //              SomeFunction_A();                 
 78 //          }                                     
 79 //                                                
 80 //          UnprotectedCode();                    
 81 //      }                                         
 82 //                                                
 83                                                   
 84 // -------------------------------------------    
 85 // Author: Andrea Dotti (15 Feb 2013): First I    
 86 //                                                
 87 // Update: Jonathan Madsen (9 Feb 2018): Repla    
 88 //      with inheritance from C++11 unique_loc    
 89 //      following member functions:               
 90 //                                                
 91 //      - unique_lock(unique_lock&& other) noe    
 92 //      - explicit unique_lock(mutex_type& m);    
 93 //      - unique_lock(mutex_type& m, std::defe    
 94 //      - unique_lock(mutex_type& m, std::try_    
 95 //      - unique_lock(mutex_type& m, std::adop    
 96 //                                                
 97 //      - template <typename Rep, typename Per    
 98 //        unique_lock(mutex_type& m,              
 99 //                   const std::chrono::durati    
100 //                                                
101 //      - template<typename Clock, typename Du    
102 //        unique_lock(mutex_type& m,              
103 //              const std::chrono::time_point<    
104 //                                                
105 //      - void lock();                            
106 //      - void unlock();                          
107 //      - bool try_lock();                        
108 //                                                
109 //      - template <typename Rep, typename Per    
110 //        bool try_lock_for(const std::chrono:    
111 //                                                
112 //      - template <typename Rep, typename Per    
113 //        bool try_lock_until(const std::chron    
114 //                                                
115 //      - void swap(unique_lock& other) noexce    
116 //      - mutex_type* release() noexcept;         
117 //      - mutex_type* mutex() const noexcept;     
118 //      - bool owns_lock() const noexcept;        
119 //      - explicit operator bool() const noexc    
120 //      - unique_lock& operator=(unique_lock&&    
121 //                                                
122 // -------------------------------------------    
123 //                                                
124 // Note that G4AutoLock is defined also for a     
125 // regarding implementation (also found in G4T    
126 //                                                
127 //                                                
128 //          NOTE ON GEANT4 SERIAL BUILDS AND M    
129 //          ==================================    
130 //                                                
131 // G4Mutex and G4RecursiveMutex are always C++    
132 // however, in serial mode, using G4MUTEXLOCK     
133 // types has no effect -- i.e. the mutexes are    
134 //                                                
135 // Additionally, when a G4Mutex or G4Recursive    
136 // and G4RecursiveAutoLock, respectively, thes    
137 // the locking and unlocking of the mutex. Reg    
138 // G4AutoLock and G4RecursiveAutoLock inherit     
139 // and std::unique_lock<std::recursive_mutex>,    
140 // that in situations (such as is needed by th    
141 // G4AutoLock and G4RecursiveAutoLock can be p    
142 // a std::unique_lock. Within these functions,    
143 // member functions are not virtual, they will    
144 // and unlocking behavior                         
145 // --> An example of this behavior can be foun    
146 //                                                
147 //  Jonathan R. Madsen (February 21, 2018)        
148 //                                                
149 /**                                               
150                                                   
151 //============================================    
152                                                   
153 void print_threading()                            
154 {                                                 
155 #ifdef G4MULTITHREADED                            
156     std::cout << "\nUsing G4MULTITHREADED vers    
157 #else                                             
158     std::cout << "\nUsing G4SERIAL version..."    
159 #endif                                            
160 }                                                 
161                                                   
162 //============================================    
163                                                   
164 typedef std::unique_lock<std::mutex> unique_lo    
165 // functions for casting G4AutoLock to std::un    
166 // that G4AutoLock is NOT polymorphic             
167 void as_unique_lock(unique_lock_t* lock) { loc    
168 void as_unique_unlock(unique_lock_t* lock) { l    
169                                                   
170 //============================================    
171                                                   
172 void run(const uint64_t& n)                       
173 {                                                 
174     // sync the threads a bit                     
175     std::this_thread::sleep_for(std::chrono::m    
176                                                   
177     // get two mutexes to avoid deadlock when     
178     G4AutoLock l32(G4TypeMutex<int32_t>(), std    
179     G4AutoLock l64(G4TypeMutex<int64_t>(), std    
180                                                   
181     // when serial: will not execute std::uniq    
182     // it overrides the member function           
183     l32.lock();                                   
184     // regardless of serial or MT: will execut    
185     // because std::unique_lock::lock() is not    
186     as_unique_lock(&l64);                         
187                                                   
188     std::cout << "Running iteration " << n <<     
189 }                                                 
190                                                   
191 //============================================    
192 // execute some work                              
193 template <typename thread_type = std::thread>     
194 void exec(uint64_t n)                             
195 {                                                 
196     // get two mutexes to avoid deadlock when     
197     G4AutoLock l32(G4TypeMutex<int32_t>(), std    
198     G4AutoLock l64(G4TypeMutex<int64_t>(), std    
199                                                   
200     std::vector<thread_type*> threads(n, nullp    
201     for(uint64_t i = 0; i < n; ++i)               
202     {                                             
203         threads[i] = new thread_type();           
204         *(threads[i]) = std::move(thread_type(    
205     }                                             
206                                                   
207     // when serial: will not execute std::uniq    
208     // it overrides the member function           
209     l32.lock();                                   
210     // regardless of serial or MT: will execut    
211     // because std::unique_lock::lock() is not    
212     as_unique_lock(&l64);                         
213                                                   
214     std::cout << "Joining..." << std::endl;       
215                                                   
216     // when serial: will not execute std::uniq    
217     // it overrides the member function           
218     l32.unlock();                                 
219     // regardless of serial or MT: will execut    
220     // because std::unique_lock::unlock() is n    
221     as_unique_unlock(&l64);                       
222                                                   
223     // NOTE ABOUT UNLOCKS:                        
224     // in MT, commenting out either               
225     //      l32.unlock();                         
226     // or                                         
227     //      as_unique_unlock(&l64);               
228     // creates a deadlock; in serial, commenti    
229     //      as_unique_unlock(&l64);               
230     // creates a deadlock but commenting out      
231     //      l32.unlock();                         
232     // does not                                   
233                                                   
234     // clean up and join                          
235     for(uint64_t i = 0; i < n; ++i)               
236     {                                             
237         threads[i]->join();                       
238         delete threads[i];                        
239     }                                             
240     threads.clear();                              
241 }                                                 
242                                                   
243 //============================================    
244                                                   
245 int main()                                        
246 {                                                 
247     print_threading();                            
248                                                   
249     uint64_t n = 30;                              
250     std::cout << "\nRunning with real threads.    
251     exec<std::thread>(n);                         
252     std::cout << "\nRunning with fake threads.    
253     exec<G4DummyThread>(n);                       
254                                                   
255 }                                                 
256                                                   
257 **/                                               
258 // -------------------------------------------    
259 #ifndef G4AUTOLOCK_HH                             
260 #define G4AUTOLOCK_HH                             
261                                                   
262 #include "G4Threading.hh"                         
263                                                   
264 #include <chrono>                                 
265 #include <iostream>                               
266 #include <mutex>                                  
267 #include <system_error>                           
268                                                   
269 // Note: Note that G4TemplateAutoLock by itsel    
270 //       cannot be shared among threads due to    
271 //                                                
272 template <typename _Mutex_t>                      
273 class G4TemplateAutoLock : public std::unique_    
274 {                                                 
275  public:                                          
276   //------------------------------------------    
277   // Some useful typedefs                         
278   //------------------------------------------    
279   using unique_lock_t = std::unique_lock<_Mute    
280   using this_type = G4TemplateAutoLock<_Mutex_    
281   using mutex_type = typename unique_lock_t::m    
282                                                   
283  public:                                          
284   //------------------------------------------    
285   // STL-consistent reference form constructor    
286   //------------------------------------------    
287                                                   
288   // reference form is consistent with STL loc    
289   // Locks the associated mutex by calling m.l    
290   // undefined if the current thread already o    
291   // the mutex is recursive                       
292   G4TemplateAutoLock(mutex_type& _mutex)          
293     : unique_lock_t(_mutex, std::defer_lock)      
294   {                                               
295     // call termination-safe locking. if seria    
296     _lock_deferred();                             
297   }                                               
298                                                   
299   // Tries to lock the associated mutex by cal    
300   // m.try_lock_for(_timeout_duration). Blocks    
301   // _timeout_duration has elapsed or the lock    
302   // first. May block for longer than _timeout    
303   template <typename Rep, typename Period>        
304   G4TemplateAutoLock(                             
305     mutex_type& _mutex,                           
306     const std::chrono::duration<Rep, Period>&     
307     : unique_lock_t(_mutex, std::defer_lock)      
308   {                                               
309     // call termination-safe locking. if seria    
310     _lock_deferred(_timeout_duration);            
311   }                                               
312                                                   
313   // Tries to lock the associated mutex by cal    
314   // m.try_lock_until(_timeout_time). Blocks u    
315   // been reached or the lock is acquired, whi    
316   // for longer than until _timeout_time has b    
317   template <typename Clock, typename Duration>    
318   G4TemplateAutoLock(                             
319     mutex_type& _mutex,                           
320     const std::chrono::time_point<Clock, Durat    
321     : unique_lock_t(_mutex, std::defer_lock)      
322   {                                               
323     // call termination-safe locking. if seria    
324     _lock_deferred(_timeout_time);                
325   }                                               
326                                                   
327   // Does not lock the associated mutex.          
328   G4TemplateAutoLock(mutex_type& _mutex, std::    
329     : unique_lock_t(_mutex, _lock)                
330   {}                                              
331                                                   
332 #ifdef G4MULTITHREADED                            
333                                                   
334   // Tries to lock the associated mutex withou    
335   // m.try_lock(). The behavior is undefined i    
336   // owns the mutex except when the mutex is r    
337   G4TemplateAutoLock(mutex_type& _mutex, std::    
338     : unique_lock_t(_mutex, _lock)                
339   {}                                              
340                                                   
341   // Assumes the calling thread already owns m    
342   G4TemplateAutoLock(mutex_type& _mutex, std::    
343     : unique_lock_t(_mutex, _lock)                
344   {}                                              
345                                                   
346 #else                                             
347                                                   
348   // serial dummy version (initializes unique_    
349   G4TemplateAutoLock(mutex_type& _mutex, std::    
350     : unique_lock_t(_mutex, std::defer_lock)      
351   {}                                              
352                                                   
353   // serial dummy version (initializes unique_    
354   G4TemplateAutoLock(mutex_type& _mutex, std::    
355     : unique_lock_t(_mutex, std::defer_lock)      
356   {}                                              
357                                                   
358 #endif  // defined(G4MULTITHREADED)               
359                                                   
360  public:                                          
361   //------------------------------------------    
362   // Backwards compatibility versions (constru    
363   //------------------------------------------    
364   G4TemplateAutoLock(mutex_type* _mutex)          
365     : unique_lock_t(*_mutex, std::defer_lock)     
366   {                                               
367     // call termination-safe locking. if seria    
368     _lock_deferred();                             
369   }                                               
370                                                   
371   G4TemplateAutoLock(mutex_type* _mutex, std::    
372     : unique_lock_t(*_mutex, _lock)               
373   {}                                              
374                                                   
375 #if defined(G4MULTITHREADED)                      
376                                                   
377   G4TemplateAutoLock(mutex_type* _mutex, std::    
378     : unique_lock_t(*_mutex, _lock)               
379   {}                                              
380                                                   
381   G4TemplateAutoLock(mutex_type* _mutex, std::    
382     : unique_lock_t(*_mutex, _lock)               
383   {}                                              
384                                                   
385 #else  // NOT defined(G4MULTITHREADED) -- i.e.    
386                                                   
387   G4TemplateAutoLock(mutex_type* _mutex, std::    
388     : unique_lock_t(*_mutex, std::defer_lock)     
389   {}                                              
390                                                   
391   G4TemplateAutoLock(mutex_type* _mutex, std::    
392     : unique_lock_t(*_mutex, std::defer_lock)     
393   {}                                              
394                                                   
395 #endif  // defined(G4MULTITHREADED)               
396                                                   
397  public:                                          
398   //------------------------------------------    
399   // Non-constructor overloads                    
400   //------------------------------------------    
401                                                   
402 #if defined(G4MULTITHREADED)                      
403                                                   
404   // overload nothing                             
405                                                   
406 #else  // NOT defined(G4MULTITHREADED) -- i.e.    
407                                                   
408   // override unique lock member functions to     
409   // but does not override in polymorphic usag    
410   void lock() {}                                  
411   void unlock() {}                                
412   bool try_lock() { return true; }                
413                                                   
414   template <typename Rep, typename Period>        
415   bool try_lock_for(const std::chrono::duratio    
416   {                                               
417     return true;                                  
418   }                                               
419                                                   
420   template <typename Clock, typename Duration>    
421   bool try_lock_until(const std::chrono::time_    
422   {                                               
423     return true;                                  
424   }                                               
425                                                   
426   void swap(this_type& other) noexcept { std::    
427   bool owns_lock() const noexcept { return fal    
428                                                   
429   // no need to overload                          
430   // explicit operator bool() const noexcept;     
431   // this_type& operator=(this_type&& other);     
432   // mutex_type* release() noexcept;              
433   // mutex_type* mutex() const noexcept;          
434                                                   
435 #endif  // defined(G4MULTITHREADED)               
436                                                   
437  private:                                         
438 // helpful macros                                 
439 #define _is_stand_mutex(_Tp) (std::is_same<_Tp    
440 #define _is_recur_mutex(_Tp) (std::is_same<_Tp    
441 #define _is_other_mutex(_Tp) (!_is_stand_mutex    
442                                                   
443   template <typename _Tp                          
444             typename std::enable_if<_is_stand_    
445   std::string GetTypeString()                     
446   {                                               
447     return "G4AutoLock<G4Mutex>";                 
448   }                                               
449                                                   
450   template <typename _Tp                          
451             typename std::enable_if<_is_recur_    
452   std::string GetTypeString()                     
453   {                                               
454     return "G4AutoLock<G4RecursiveMutex>";        
455   }                                               
456                                                   
457   template <typename _Tp                          
458             typename std::enable_if<_is_other_    
459   std::string GetTypeString()                     
460   {                                               
461     return "G4AutoLock<UNKNOWN_MUTEX>";           
462   }                                               
463                                                   
464 // pollution is bad                               
465 #undef _is_stand_mutex                            
466 #undef _is_recur_mutex                            
467 #undef _is_other_mutex                            
468                                                   
469   // used in _lock_deferred chrono variants to    
470   template <typename _Tp>                         
471   void suppress_unused_variable(const _Tp&)       
472   {}                                              
473                                                   
474   //==========================================    
475   // NOTE on _lock_deferred(...) variants:        
476   //      a system_error in lock means that th    
477   //      we want to throw the error that come    
478   //      mutex so that we know there is a mem    
479   //      if the mutex is valid, this will hol    
480   //      finishes                                
481                                                   
482   // sometimes certain destructors use locks,     
483   // the object is leaked. When this occurs, t    
484   // (i.e. the real or implied "return 0" part    
485   // on Geant4 object after some static mutex     
486   // to the error code (typically on Clang com    
487   //      libc++abi.dylib: terminating with un    
488   //      std::__1::system_error: mutex lock f    
489   // this function protects against this failu    
490   // these issues have been resolved              
491                                                   
492   //==========================================    
493   // standard locking                             
494   inline void _lock_deferred()                    
495   {                                               
496 #if defined(G4MULTITHREADED)                      
497     try                                           
498     {                                             
499       this->unique_lock_t::lock();                
500     } catch(std::system_error& e)                 
501     {                                             
502       PrintLockErrorMessage(e);                   
503     }                                             
504 #endif                                            
505   }                                               
506                                                   
507   //==========================================    
508   // Tries to lock the associated mutex by cal    
509   // m.try_lock_for(_timeout_duration). Blocks    
510   // _timeout_duration has elapsed or the lock    
511   // first. May block for longer than _timeout    
512   template <typename Rep, typename Period>        
513   void _lock_deferred(                            
514     const std::chrono::duration<Rep, Period>&     
515   {                                               
516 #if defined(G4MULTITHREADED)                      
517     try                                           
518     {                                             
519       this->unique_lock_t::try_lock_for(_timeo    
520     } catch(std::system_error& e)                 
521     {                                             
522       PrintLockErrorMessage(e);                   
523     }                                             
524 #else                                             
525     suppress_unused_variable(_timeout_duration    
526 #endif                                            
527   }                                               
528                                                   
529   //==========================================    
530   // Tries to lock the associated mutex by cal    
531   // m.try_lock_until(_timeout_time). Blocks u    
532   // been reached or the lock is acquired, whi    
533   // for longer than until _timeout_time has b    
534   template <typename Clock, typename Duration>    
535   void _lock_deferred(                            
536     const std::chrono::time_point<Clock, Durat    
537   {                                               
538 #if defined(G4MULTITHREADED)                      
539     try                                           
540     {                                             
541       this->unique_lock_t::try_lock_until(_tim    
542     } catch(std::system_error& e)                 
543     {                                             
544       PrintLockErrorMessage(e);                   
545     }                                             
546 #else                                             
547     suppress_unused_variable(_timeout_time);      
548 #endif                                            
549   }                                               
550                                                   
551   //==========================================    
552   // the message for what mutex lock fails due    
553   // at termination                               
554   void PrintLockErrorMessage(std::system_error    
555   {                                               
556     // use std::cout/std::endl to avoid includ    
557     using std::cout;                              
558     using std::endl;                              
559     // the error that comes from locking an un    
560 #if defined(G4VERBOSE)                            
561     cout << "Non-critical error: mutex lock fa    
562          << GetTypeString<mutex_type>() << ".     
563          << "If the app is terminating, Geant4    
564          << "delete an allocated resource and     
565          << "being called after the statics we    
566          << "Exception: [code: " << e.code() <    
567          << endl;                                 
568 #else                                             
569     suppress_unused_variable(e);                  
570 #endif                                            
571   }                                               
572 };                                                
573                                                   
574 // -------------------------------------------    
575 //                                                
576 //      Use the non-template types below:         
577 //          - G4AutoLock with G4Mutex             
578 //          - G4RecursiveAutoLock with G4Recur    
579 //                                                
580 // -------------------------------------------    
581                                                   
582 using G4AutoLock          = G4TemplateAutoLock    
583 using G4RecursiveAutoLock = G4TemplateAutoLock    
584                                                   
585 // provide abbriviated type if another mutex t    
586 // aside from above                               
587 template <typename _Tp>                           
588 using G4TAutoLock = G4TemplateAutoLock<_Tp>;      
589                                                   
590 #endif  // G4AUTOLOCK_HH                          
591