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 10.4.p1)


  1 //                                                  1 //
  2 // *******************************************      2 // ********************************************************************
  3 // * License and Disclaimer                         3 // * License and Disclaimer                                           *
  4 // *                                                4 // *                                                                  *
  5 // * The  Geant4 software  is  copyright of th      5 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
  6 // * the Geant4 Collaboration.  It is provided      6 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
  7 // * conditions of the Geant4 Software License      7 // * conditions of the Geant4 Software License,  included in the file *
  8 // * LICENSE and available at  http://cern.ch/      8 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
  9 // * include a list of copyright holders.           9 // * include a list of copyright holders.                             *
 10 // *                                               10 // *                                                                  *
 11 // * Neither the authors of this software syst     11 // * Neither the authors of this software system, nor their employing *
 12 // * institutes,nor the agencies providing fin     12 // * institutes,nor the agencies providing financial support for this *
 13 // * work  make  any representation or  warran     13 // * work  make  any representation or  warranty, express or implied, *
 14 // * regarding  this  software system or assum     14 // * regarding  this  software system or assume any liability for its *
 15 // * use.  Please see the license in the file      15 // * use.  Please see the license in the file  LICENSE  and URL above *
 16 // * for the full disclaimer and the limitatio     16 // * for the full disclaimer and the limitation of liability.         *
 17 // *                                               17 // *                                                                  *
 18 // * This  code  implementation is the result      18 // * This  code  implementation is the result of  the  scientific and *
 19 // * technical work of the GEANT4 collaboratio     19 // * technical work of the GEANT4 collaboration.                      *
 20 // * By using,  copying,  modifying or  distri     20 // * By using,  copying,  modifying or  distributing the software (or *
 21 // * any work based  on the software)  you  ag     21 // * any work based  on the software)  you  agree  to acknowledge its *
 22 // * use  in  resulting  scientific  publicati     22 // * use  in  resulting  scientific  publications,  and indicate your *
 23 // * acceptance of all terms of the Geant4 Sof     23 // * acceptance of all terms of the Geant4 Software license.          *
 24 // *******************************************     24 // ********************************************************************
 25 //                                                 25 //
 26 // G4Autolock                                  <<  26 // $Id$
                                                   >>  27 //
                                                   >>  28 // ---------------------------------------------------------------
                                                   >>  29 // GEANT 4 class header file
 27 //                                                 30 //
 28 // Class Description:                              31 // Class Description:
 29 //                                                 32 //
 30 // This class provides a mechanism to create a     33 // This class provides a mechanism to create a mutex and locks/unlocks it.
 31 // Can be used by applications to implement in     34 // Can be used by applications to implement in a portable way a mutexing logic.
 32 // Usage Example:                                  35 // Usage Example:
 33 //                                                 36 //
 34 //      #include "G4Threading.hh"                  37 //      #include "G4Threading.hh"
 35 //      #include "G4AutoLock.hh"                   38 //      #include "G4AutoLock.hh"
 36 //                                             <<  39 //      /* somehwere */
 37 //      // defined somewhere -- static so all  <<  40 //      G4Mutex aMutex = G4MUTEX_INITIALIZER;
 38 //      static G4Mutex aMutex;                 <<  41 //      /*
 39 //                                             <<  42 //       somewhere else:
 40 //      // somewhere else:                     <<  43 //       The G4AutoLock instance will automatically unlock the mutex when it
 41 //      // The G4AutoLock instance will automa <<  44 //       goes out of scope, lock and unlock method are anyway available for
 42 //      // goes out of scope. One typically de <<  45 //       explicit handling of mutex lock. */
 43 //      // there is thread-safe code following <<  46 //      G4AutoLock l(&aMutex);
 44 //                                             <<  47 //      ProtectedCode();
 45 //      {                                      <<  48 //      l.unlock(); //explicit unlock
 46 //          G4AutoLock l(&aMutex);             << 
 47 //          ProtectedCode();                   << 
 48 //      }                                      << 
 49 //                                             << 
 50 //      UnprotectedCode();                         49 //      UnprotectedCode();
                                                   >>  50 //      l.lock();   //explicit lock
 51 //                                                 51 //
 52 //      // When ProtectedCode() is calling a f <<  52 // Note that G4AutoLock is defined also for a sequential Geant4 build,
 53 //      // a normal G4AutoLock + G4Mutex will  <<  53 // but has no effect.
 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                                                    54 
 84 // ------------------------------------------- <<  55 // ---------------------------------------------------------------
 85 // Author: Andrea Dotti (15 Feb 2013): First I     56 // Author: Andrea Dotti (15 Feb 2013): First Implementation
 86 //                                             <<  57 // ---------------------------------------------------------------
 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                                                    58 
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                              59 #ifndef G4AUTOLOCK_HH
260 #define G4AUTOLOCK_HH                              60 #define G4AUTOLOCK_HH
261                                                    61 
262 #include "G4Threading.hh"                          62 #include "G4Threading.hh"
263                                                    63 
264 #include <chrono>                              << 
265 #include <iostream>                            << 
266 #include <mutex>                               << 
267 #include <system_error>                        << 
268                                                << 
269 // Note: Note that G4TemplateAutoLock by itsel     64 // Note: Note that G4TemplateAutoLock by itself is not thread-safe and
270 //       cannot be shared among threads due to     65 //       cannot be shared among threads due to the locked switch
271 //                                                 66 //
272 template <typename _Mutex_t>                   <<  67 template<class M, typename L, typename U>
273 class G4TemplateAutoLock : public std::unique_ <<  68 class G4TemplateAutoLock
274 {                                                  69 {
275  public:                                       <<  70   public:
276   //------------------------------------------ <<  71 
277   // Some useful typedefs                      <<  72     G4TemplateAutoLock(M* mtx, L l, U u) : locked(false), _m(mtx), _l(l), _u(u)
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     {                                              73     {
502       PrintLockErrorMessage(e);                <<  74         lock();
503     }                                              75     }
504 #endif                                         << 
505   }                                            << 
506                                                    76 
507   //========================================== <<  77     virtual ~G4TemplateAutoLock()
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     {                                              78     {
522       PrintLockErrorMessage(e);                <<  79         unlock();
523     }                                              80     }
524 #else                                          <<  81 
525     suppress_unused_variable(_timeout_duration <<  82     inline void unlock() {
526 #endif                                         <<  83         if ( !locked ) return;
527   }                                            <<  84         _u(_m);
528                                                <<  85         locked = false;
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     }                                              86     }
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                                                    87 
574 // ------------------------------------------- <<  88     inline void lock() {
575 //                                             <<  89         if ( locked ) return;
576 //      Use the non-template types below:      <<  90         _l(_m);
577 //          - G4AutoLock with G4Mutex          <<  91         locked = true;
578 //          - G4RecursiveAutoLock with G4Recur <<  92     }
579 //                                             << 
580 // ------------------------------------------- << 
581                                                    93 
582 using G4AutoLock          = G4TemplateAutoLock <<  94   private:
583 using G4RecursiveAutoLock = G4TemplateAutoLock << 
584                                                    95 
585 // provide abbriviated type if another mutex t <<  96     // Disable copy and assignement operators
586 // aside from above                            <<  97     //
587 template <typename _Tp>                        <<  98     G4TemplateAutoLock( const G4TemplateAutoLock& rhs );
588 using G4TAutoLock = G4TemplateAutoLock<_Tp>;   <<  99     G4TemplateAutoLock& operator= ( const G4TemplateAutoLock& rhs );
                                                   >> 100 
                                                   >> 101   private:
                                                   >> 102     G4bool locked;
                                                   >> 103     M* _m;
                                                   >> 104     L _l;
                                                   >> 105     U _u;
                                                   >> 106 };
                                                   >> 107 
                                                   >> 108 struct G4ImpMutexAutoLock
                                                   >> 109   : public G4TemplateAutoLock<G4Mutex,thread_lock,thread_unlock>
                                                   >> 110 {
                                                   >> 111     G4ImpMutexAutoLock(G4Mutex* mtx)
                                                   >> 112       : G4TemplateAutoLock<G4Mutex, thread_lock, thread_unlock>
                                                   >> 113         (mtx, &G4MUTEXLOCK, &G4MUTEXUNLOCK) {}
                                                   >> 114 };
                                                   >> 115 typedef G4ImpMutexAutoLock G4AutoLock;
589                                                   116 
590 #endif  // G4AUTOLOCK_HH                       << 117 #endif //G4AUTOLOCK_HH
591                                                   118