Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:58:42

0001 //
0002 // ********************************************************************
0003 // * License and Disclaimer                                           *
0004 // *                                                                  *
0005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
0006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
0007 // * conditions of the Geant4 Software License,  included in the file *
0008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
0009 // * include a list of copyright holders.                             *
0010 // *                                                                  *
0011 // * Neither the authors of this software system, nor their employing *
0012 // * institutes,nor the agencies providing financial support for this *
0013 // * work  make  any representation or  warranty, express or implied, *
0014 // * regarding  this  software system or assume any liability for its *
0015 // * use.  Please see the license in the file  LICENSE  and URL above *
0016 // * for the full disclaimer and the limitation of liability.         *
0017 // *                                                                  *
0018 // * This  code  implementation is the result of  the  scientific and *
0019 // * technical work of the GEANT4 collaboration.                      *
0020 // * By using,  copying,  modifying or  distributing the software (or *
0021 // * any work based  on the software)  you  agree  to acknowledge its *
0022 // * use  in  resulting  scientific  publications,  and indicate your *
0023 // * acceptance of all terms of the Geant4 Software license.          *
0024 // ********************************************************************
0025 //
0026 // G4MTBarrier
0027 //
0028 // Class description:
0029 //
0030 // This class defines a synchronization point between threads: a master
0031 // and a pool of workers.
0032 // A barrier is a (shared) instance of this class. Master sets the number
0033 // of active threads to wait for, then it waits for workers to become ready
0034 // calling the method WaitForReadyWorkers().
0035 // The master thread will block on this call.
0036 // Each of the workers calls ThisWorkerReady() when it is ready to continue.
0037 // It will block on this call.
0038 // When all worker threads have called ThisWorkerReady and are waiting the
0039 // master will release the barrier and execution will continue.
0040 //
0041 // User code can implement more advanced barriers that require exchange
0042 // of a message between master and threads inheriting from this class as in:
0043 //    class Derived : public G4MTBarrier {
0044 //       G4Mutex mutexForMessage;
0045 //       SomeType message;
0046 //       void MethodCalledByWorkers() {
0047 //            G4MTBarrirer::ThisWorkerReady();
0048 //            G4AutoLock l(&mutexForMessage);
0049 //            [... process message ...]
0050 //       }
0051 //      void WaitForReadyWorkers() override {
0052 //             Wait(); <== Mandatory
0053 //             [.. process message ...] <== User code between the two calls
0054 //             ReleaseBarrier(); <== Mandatory
0055 //      }
0056 //      void MethodCalledByMaster() { WaitForReadyWorkers(); }
0057 //    }
0058 // User code can also achieve the same results as before using the granular
0059 // methods LoopWaitingWorkers and ResetCounterAndBroadcast methods in the
0060 // master. For examples of usage of this class see G4MTRunManager
0061 //
0062 // =====================================
0063 // Barriers mechanism
0064 // =====================================
0065 // We define a barrier has a point in which threads synchronize.
0066 // When workers threads reach a barrier they wait for the master thread a
0067 // signal that they can continue. The master thread broadcast this signal
0068 // only when all worker threads have reached this point.
0069 // Currently only three points require this sync in the life-time of a G4
0070 // application: just before and just after the for-loop controlling the
0071 // thread event-loop and between runs.
0072 //
0073 // The basic algorithm of each barrier works like this:
0074 // In the master:
0075 //   WaitWorkers()
0076 //   {
0077 //    while (true)
0078 //    {
0079 //     G4AutoLock l(&counterMutex);                          || Mutex is locked
0080 //     (1) if ( counter == nActiveThreads ) break; G4CONDITIONWAIT(
0081 //     &conditionOnCounter, &counterMutex); || Mutex is atomically released and
0082 //     wait, upon return locked (2)
0083 //    }                                                      || unlock mutex
0084 //    G4AutoLock l(&counterMutex);                           || lock again mutex
0085 //    (3) G4CONDITIONBROADCAST( &doSomethingCanStart );          || Here mutex
0086 //    is locked (4)
0087 //   }                                                       || final unlock (5)
0088 // In the workers:
0089 //   WaitSignalFromMaster()
0090 //   {
0091 //    G4AutoLock l(&counterMutex);                           || (6)
0092 //    ++counter;
0093 //    G4CONDITIONBROADCAST(&conditionOnCounter);             || (7)
0094 //    G4CONDITIONWAIT( &doSomethingCanStart , &counterMutex);|| (8)
0095 //   }
0096 // Each barrier requires 2 conditions and one mutex, plus a counter.
0097 // Important note: the thread calling broadcast should hold the mutex
0098 // before calling broadcast to obtain predictible behavior
0099 // http://pubs.opengroup.org/onlinepubs/7908799/xsh/pthread_cond_broadcast.html
0100 // Also remember that the wait for condition will atomically release the mutex
0101 // and wait on condition, but it will lock again on mutex when returning
0102 // Here it is how the control flows.
0103 // Imagine master starts and only one worker (nActiveThreads==1)
0104 // Master       |    Worker        | counter | Who holds mutex
0105 // Gets to (1)  |   Blocks on (6)  | 0       | M
0106 // Waits in (2) |                  | 0       | -
0107 //              |  Arrives to (7)  | 1       | W
0108 //              |  Waits in (8)    | 1       | -
0109 // Gets to (1)  |                  | 1       | M
0110 // Jumps to (3) |                  | 1       | M
0111 // End          |                  | 1       | -
0112 //              | End              | 1       | -
0113 // Similarly for more than one worker threads or if worker starts
0114 
0115 // Author: A.Dotti (SLAC), 10 February 2016
0116 // --------------------------------------------------------------------
0117 #ifndef G4MTBARRIER_HH
0118 #define G4MTBARRIER_HH
0119 
0120 #include "G4Threading.hh"
0121 
0122 class G4MTBarrier
0123 {
0124  public:
0125   G4MTBarrier()
0126     : G4MTBarrier(1)
0127   {}
0128   virtual ~G4MTBarrier() {}
0129   G4MTBarrier(const G4MTBarrier&) = delete;
0130   G4MTBarrier& operator=(const G4MTBarrier&) = delete;
0131 
0132   // on explicitly defaulted move at
0133   // https://msdn.microsoft.com/en-us/library/dn457344.aspx
0134   // G4MTBarrier(G4MTBarrier&&) = default;
0135   // G4MTBarrier& operator=(G4MTBarrier&&)  = default;
0136 
0137   G4MTBarrier(unsigned int numThreads);
0138   void ThisWorkerReady();
0139   virtual void WaitForReadyWorkers();
0140   inline void SetActiveThreads(unsigned int val) { m_numActiveThreads = val; }
0141   void ResetCounter();
0142   unsigned int GetCounter();
0143   void Wait();
0144   void ReleaseBarrier();
0145   inline void Wait(unsigned int numt)
0146   {
0147     SetActiveThreads(numt);
0148     Wait();
0149   }
0150 
0151  private:
0152   unsigned int m_numActiveThreads = 0;
0153   unsigned int m_counter          = 0;
0154   G4Mutex m_mutex;
0155   G4Condition m_counterChanged;
0156   G4Condition m_continue;
0157 };
0158 
0159 #endif