Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-23 07:41:56

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 /// \file G4atomic.hh
0027 /// \brief Definition of the G4atomic class
0028 ///
0029 /// This is an friendly implementation of the STL atomic class.
0030 ///     This class has the same interface as the STL atomic but can be used
0031 ///     in an extremely similar fashion to plain old data (POD) types.
0032 ///     In other words, the copy constructor and assignment operators are
0033 ///     defined, and a load() does not need to be called to get the POD
0034 ///     value.
0035 ///
0036 /// IMPORTANT: Care must be taken when using this class as a RHS term.
0037 ///     The best use case scenario for this class is as a LHS term that is
0038 ///     only used as a RHS term outside of the multithreaded operations on it.
0039 ///
0040 /// FOR EXAMPLE:
0041 /// ```
0042 ///     Proper use:
0043 ///         Goal: sum energy deposited in run
0044 ///         Impl: Is a member variable of derived
0045 ///                   G4VUserActionInitialization (of which there will
0046 ///                   always be just one instance). Accumulate
0047 ///                   thread-local energy deposit into EventAction,
0048 ///                   add to ActionInit at end of event, print sum
0049 ///                   on master EndOfRunAction
0050 ///         Why: the sum is only a LHS term
0051 ///     Improper use:
0052 ///         Goal: compute error during event processing
0053 ///         Impl: sum += x; sum_sq += x*x; counts++;
0054 ///               error = sqrt(sum_sq/(sum*sum) - 1/counts;
0055 ///               (where sum, sum_sq, counts are G4atomics)
0056 ///         Why: This will work but error can/will be wrong when
0057 ///              sum, sum_sq, and counts are updated by another thread
0058 ///              while error is being calculated, i.e. they are used as
0059 ///              RHS terms
0060 /// ```
0061 //
0062 //
0063 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0064 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0065 
0066 #ifndef G4atomic_hh_
0067 #define G4atomic_hh_
0068 
0069 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0070 
0071 #ifdef G4MULTITHREADED
0072 
0073 #  include "G4atomic_defines.hh"
0074 
0075 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0076 
0077 template<typename _Tp>
0078 class G4atomic
0079 {
0080   public:
0081     typedef typename std::atomic<_Tp> base_type;
0082     typedef _Tp value_type;
0083 
0084   private:
0085     using mem_ord = std::memory_order;
0086 
0087   public:
0088     // constructors
0089     explicit G4atomic(mem_ord mo = std::memory_order_acq_rel) : fMemOrder(mo)
0090     {
0091       atomics::set(&fvalue, value_type());
0092     }
0093 
0094     explicit G4atomic(const value_type& _init, mem_ord mo = std::memory_order_acq_rel)
0095       : fMemOrder(mo)
0096     {
0097       atomics::set(&fvalue, _init);
0098     }
0099 
0100     // copy-constructor from pure C++11 atomic
0101     explicit G4atomic(const base_type& rhs, mem_ord mo = std::memory_order_acq_rel) : fMemOrder(mo)
0102     {
0103       atomics::set(&fvalue, rhs);
0104     }
0105 
0106     // copy-constructor
0107     explicit G4atomic(const G4atomic& rhs) : fMemOrder(rhs.fMemOrder)
0108     {
0109       atomics::set(&fvalue, rhs.base());
0110     }
0111 
0112     // assignment operators
0113     G4atomic& operator=(const G4atomic& rhs)
0114     {
0115       if (this != &rhs) atomics::set(&fvalue, rhs.fvalue);
0116       return *this;
0117     }
0118 
0119     G4atomic& operator=(const value_type& rhs)
0120     {
0121       atomics::set(&fvalue, rhs);
0122       return *this;
0123     }
0124 
0125     G4atomic& operator=(const base_type& rhs)
0126     {
0127       atomics::set(&fvalue, rhs);
0128       return *this;
0129     }
0130 
0131     // destructor
0132     ~G4atomic() { fvalue.~base_type(); }
0133 
0134     // base version
0135     base_type& base() { return fvalue; }
0136     const base_type& base() const { return fvalue; }
0137     base_type& base() volatile { return fvalue; }
0138     const base_type& base() const volatile { return fvalue; }
0139 
0140     // check if atomic is lock-free
0141     bool is_lock_free() const { return fvalue.is_lock_free(); }
0142     bool is_lock_free() const volatile { return fvalue.is_lock_free(); }
0143 
0144     // store functions
0145     void store(_Tp _desired, mem_ord mo = std::memory_order_seq_cst)
0146     {
0147       atomics::set(fvalue, _desired, mo);
0148     }
0149     void store(_Tp _desired, mem_ord mo = std::memory_order_seq_cst) volatile
0150     {
0151       atomics::set(fvalue, _desired, mo);
0152     }
0153 
0154     // load functions
0155     _Tp load(mem_ord mo = std::memory_order_seq_cst) const { return atomics::get(fvalue, mo); }
0156     _Tp load(mem_ord mo = std::memory_order_seq_cst) const volatile
0157     {
0158       return atomics::get(fvalue, mo);
0159     }
0160 
0161     // implicit conversion functions
0162     operator _Tp() const { return this->load(); }
0163     operator _Tp() const volatile { return this->load(); }
0164 
0165     operator base_type&() const { return fvalue; }
0166 
0167     // compare-and-swap functions
0168     bool compare_exchange_weak(_Tp& _expected, _Tp _desired, mem_ord _success, mem_ord _failure)
0169     {
0170       return fvalue.compare_exchange_weak(_expected, _desired, _success, _failure);
0171     }
0172     bool compare_exchange_weak(_Tp& _expected, _Tp _desired, mem_ord _success,
0173                                mem_ord _failure) volatile
0174     {
0175       return fvalue.compare_exchange_weak(_expected, _desired, _success, _failure);
0176     }
0177 
0178     bool compare_exchange_weak(_Tp& _expected, _Tp _desired, mem_ord _order)
0179     {
0180       return fvalue.compare_exchange_weak(_expected, _desired, _order);
0181     }
0182     bool compare_exchange_weak(_Tp& _expected, _Tp _desired, mem_ord _order) volatile
0183     {
0184       return fvalue.compare_exchange_weak(_expected, _desired, _order);
0185     }
0186 
0187     bool compare_exchange_strong(_Tp& _expected, _Tp _desired, mem_ord _success, mem_ord _failure)
0188     {
0189       return fvalue.compare_exchange_weak(_expected, _desired, _success, _failure);
0190     }
0191     bool compare_exchange_strong(_Tp& _expected, _Tp _desired, mem_ord _success,
0192                                  mem_ord _failure) volatile
0193     {
0194       return fvalue.compare_exchange_weak(_expected, _desired, _success, _failure);
0195     }
0196 
0197     bool compare_exchange_strong(_Tp& _expected, _Tp _desired, mem_ord _order)
0198     {
0199       return fvalue.compare_exchange_weak(_expected, _desired, _order);
0200     }
0201     bool compare_exchange_strong(_Tp& _expected, _Tp _desired, mem_ord _order) volatile
0202     {
0203       return fvalue.compare_exchange_weak(_expected, _desired, _order);
0204     }
0205 
0206     // value_type operators
0207     G4atomic& operator+=(const value_type& rhs)
0208     {
0209       atomics::increment(&fvalue, rhs, fMemOrder);
0210       return *this;
0211     }
0212     G4atomic& operator-=(const value_type& rhs)
0213     {
0214       atomics::decrement(&fvalue, rhs, fMemOrder);
0215       return *this;
0216     }
0217     G4atomic& operator*=(const value_type& rhs)
0218     {
0219       atomics::multiply(&fvalue, rhs, fMemOrder);
0220       return *this;
0221     }
0222     G4atomic& operator/=(const value_type& rhs)
0223     {
0224       atomics::divide(&fvalue, rhs, fMemOrder);
0225       return *this;
0226     }
0227 
0228     // atomic operators
0229     G4atomic& operator+=(const G4atomic& rhs)
0230     {
0231       atomics::increment(&fvalue, rhs.fvalue);
0232       return *this;
0233     }
0234     G4atomic& operator-=(const G4atomic& rhs)
0235     {
0236       atomics::decrement(&fvalue, rhs.fvalue);
0237       return *this;
0238     }
0239     G4atomic& operator*=(const G4atomic& rhs)
0240     {
0241       atomics::multiply(&fvalue, rhs.fvalue);
0242       return *this;
0243     }
0244     G4atomic& operator/=(const G4atomic& rhs)
0245     {
0246       atomics::divide(&fvalue, rhs.fvalue);
0247       return *this;
0248     }
0249 
0250     G4atomic& operator+=(const G4atomic& rhs) volatile
0251     {
0252       atomics::increment(&fvalue, rhs.fvalue);
0253       return *this;
0254     }
0255     G4atomic& operator-=(const G4atomic& rhs) volatile
0256     {
0257       atomics::decrement(&fvalue, rhs.fvalue);
0258       return *this;
0259     }
0260     G4atomic& operator*=(const G4atomic& rhs) volatile
0261     {
0262       atomics::multiply(&fvalue, rhs.fvalue);
0263       return *this;
0264     }
0265     G4atomic& operator/=(const G4atomic& rhs) volatile
0266     {
0267       atomics::divide(&fvalue, rhs.fvalue);
0268       return *this;
0269     }
0270 
0271     // STL atomic operators
0272     G4atomic& operator+=(const std::atomic<_Tp>& rhs)
0273     {
0274       atomics::increment(&fvalue, rhs, fMemOrder);
0275       return *this;
0276     }
0277     G4atomic& operator-=(const std::atomic<_Tp>& rhs)
0278     {
0279       atomics::decrement(&fvalue, rhs, fMemOrder);
0280       return *this;
0281     }
0282     G4atomic& operator*=(const std::atomic<_Tp>& rhs)
0283     {
0284       atomics::multiply(&fvalue, rhs, fMemOrder);
0285       return *this;
0286     }
0287     G4atomic& operator/=(const std::atomic<_Tp>& rhs)
0288     {
0289       atomics::divide(&fvalue, rhs, fMemOrder);
0290       return *this;
0291     }
0292 
0293     G4atomic& operator+=(const std::atomic<_Tp>& rhs) volatile
0294     {
0295       atomics::increment(&fvalue, rhs, fMemOrder);
0296       return *this;
0297     }
0298     G4atomic& operator-=(const std::atomic<_Tp>& rhs) volatile
0299     {
0300       atomics::decrement(&fvalue, rhs, fMemOrder);
0301       return *this;
0302     }
0303     G4atomic& operator*=(const std::atomic<_Tp>& rhs) volatile
0304     {
0305       atomics::multiply(&fvalue, rhs, fMemOrder);
0306       return *this;
0307     }
0308     G4atomic& operator/=(const std::atomic<_Tp>& rhs) volatile
0309     {
0310       atomics::divide(&fvalue, rhs, fMemOrder);
0311       return *this;
0312     }
0313 
0314     // increment operators
0315     value_type operator++()
0316     {
0317       value_type _tmp = ++fvalue;
0318       return _tmp;
0319     }
0320     value_type operator++(int)
0321     {
0322       value_type _tmp = fvalue++;
0323       return _tmp;
0324     }
0325 
0326     value_type operator--()
0327     {
0328       value_type _tmp = --fvalue;
0329       return _tmp;
0330     }
0331     value_type operator--(int)
0332     {
0333       value_type _tmp = fvalue--;
0334       return _tmp;
0335     }
0336 
0337   protected:
0338     base_type fvalue;
0339     mem_ord fMemOrder;
0340 };
0341 
0342 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0343 
0344 #else  // ! G4MULTITHREADED
0345 
0346 template<typename _Tp>
0347 using G4atomic = _Tp;
0348 
0349 #endif  // G4MULTITHREADED
0350 
0351 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0352 
0353 #endif  // G4atomic_hh_