354 lines
11 KiB
C++
354 lines
11 KiB
C++
//
|
|
// ********************************************************************
|
|
// * License and Disclaimer *
|
|
// * *
|
|
// * The Geant4 software is copyright of the Copyright Holders of *
|
|
// * the Geant4 Collaboration. It is provided under the terms and *
|
|
// * conditions of the Geant4 Software License, included in the file *
|
|
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
|
// * include a list of copyright holders. *
|
|
// * *
|
|
// * Neither the authors of this software system, nor their employing *
|
|
// * institutes,nor the agencies providing financial support for this *
|
|
// * work make any representation or warranty, express or implied, *
|
|
// * regarding this software system or assume any liability for its *
|
|
// * use. Please see the license in the file LICENSE and URL above *
|
|
// * for the full disclaimer and the limitation of liability. *
|
|
// * *
|
|
// * This code implementation is the result of the scientific and *
|
|
// * technical work of the GEANT4 collaboration. *
|
|
// * By using, copying, modifying or distributing the software (or *
|
|
// * any work based on the software) you agree to acknowledge its *
|
|
// * use in resulting scientific publications, and indicate your *
|
|
// * acceptance of all terms of the Geant4 Software license. *
|
|
// ********************************************************************
|
|
//
|
|
/// \file G4atomic.hh
|
|
/// \brief Definition of the G4atomic class
|
|
///
|
|
/// This is an friendly implementation of the STL atomic class.
|
|
/// This class has the same interface as the STL atomic but can be used
|
|
/// in an extremely similar fashion to plain old data (POD) types.
|
|
/// In other words, the copy constructor and assignment operators are
|
|
/// defined, and a load() does not need to be called to get the POD
|
|
/// value.
|
|
///
|
|
/// IMPORTANT: Care must be taken when using this class as a RHS term.
|
|
/// The best use case scenario for this class is as a LHS term that is
|
|
/// only used as a RHS term outside of the multithreaded operations on it.
|
|
///
|
|
/// FOR EXAMPLE:
|
|
/// ```
|
|
/// Proper use:
|
|
/// Goal: sum energy deposited in run
|
|
/// Impl: Is a member variable of derived
|
|
/// G4VUserActionInitialization (of which there will
|
|
/// always be just one instance). Accumulate
|
|
/// thread-local energy deposit into EventAction,
|
|
/// add to ActionInit at end of event, print sum
|
|
/// on master EndOfRunAction
|
|
/// Why: the sum is only a LHS term
|
|
/// Improper use:
|
|
/// Goal: compute error during event processing
|
|
/// Impl: sum += x; sum_sq += x*x; counts++;
|
|
/// error = sqrt(sum_sq/(sum*sum) - 1/counts;
|
|
/// (where sum, sum_sq, counts are G4atomics)
|
|
/// Why: This will work but error can/will be wrong when
|
|
/// sum, sum_sq, and counts are updated by another thread
|
|
/// while error is being calculated, i.e. they are used as
|
|
/// RHS terms
|
|
/// ```
|
|
//
|
|
//
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
#ifndef G4atomic_hh_
|
|
#define G4atomic_hh_
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
#ifdef G4MULTITHREADED
|
|
|
|
# include "G4atomic_defines.hh"
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
template<typename _Tp>
|
|
class G4atomic
|
|
{
|
|
public:
|
|
typedef typename std::atomic<_Tp> base_type;
|
|
typedef _Tp value_type;
|
|
|
|
private:
|
|
using mem_ord = std::memory_order;
|
|
|
|
public:
|
|
// constructors
|
|
explicit G4atomic(mem_ord mo = std::memory_order_acq_rel) : fMemOrder(mo)
|
|
{
|
|
atomics::set(&fvalue, value_type());
|
|
}
|
|
|
|
explicit G4atomic(const value_type& _init, mem_ord mo = std::memory_order_acq_rel)
|
|
: fMemOrder(mo)
|
|
{
|
|
atomics::set(&fvalue, _init);
|
|
}
|
|
|
|
// copy-constructor from pure C++11 atomic
|
|
explicit G4atomic(const base_type& rhs, mem_ord mo = std::memory_order_acq_rel) : fMemOrder(mo)
|
|
{
|
|
atomics::set(&fvalue, rhs);
|
|
}
|
|
|
|
// copy-constructor
|
|
explicit G4atomic(const G4atomic& rhs) : fMemOrder(rhs.fMemOrder)
|
|
{
|
|
atomics::set(&fvalue, rhs.base());
|
|
}
|
|
|
|
// assignment operators
|
|
G4atomic& operator=(const G4atomic& rhs)
|
|
{
|
|
if (this != &rhs) atomics::set(&fvalue, rhs.fvalue);
|
|
return *this;
|
|
}
|
|
|
|
G4atomic& operator=(const value_type& rhs)
|
|
{
|
|
atomics::set(&fvalue, rhs);
|
|
return *this;
|
|
}
|
|
|
|
G4atomic& operator=(const base_type& rhs)
|
|
{
|
|
atomics::set(&fvalue, rhs);
|
|
return *this;
|
|
}
|
|
|
|
// destructor
|
|
~G4atomic() { fvalue.~base_type(); }
|
|
|
|
// base version
|
|
base_type& base() { return fvalue; }
|
|
const base_type& base() const { return fvalue; }
|
|
base_type& base() volatile { return fvalue; }
|
|
const base_type& base() const volatile { return fvalue; }
|
|
|
|
// check if atomic is lock-free
|
|
bool is_lock_free() const { return fvalue.is_lock_free(); }
|
|
bool is_lock_free() const volatile { return fvalue.is_lock_free(); }
|
|
|
|
// store functions
|
|
void store(_Tp _desired, mem_ord mo = std::memory_order_seq_cst)
|
|
{
|
|
atomics::set(fvalue, _desired, mo);
|
|
}
|
|
void store(_Tp _desired, mem_ord mo = std::memory_order_seq_cst) volatile
|
|
{
|
|
atomics::set(fvalue, _desired, mo);
|
|
}
|
|
|
|
// load functions
|
|
_Tp load(mem_ord mo = std::memory_order_seq_cst) const { return atomics::get(fvalue, mo); }
|
|
_Tp load(mem_ord mo = std::memory_order_seq_cst) const volatile
|
|
{
|
|
return atomics::get(fvalue, mo);
|
|
}
|
|
|
|
// implicit conversion functions
|
|
operator _Tp() const { return this->load(); }
|
|
operator _Tp() const volatile { return this->load(); }
|
|
|
|
operator base_type&() const { return fvalue; }
|
|
|
|
// compare-and-swap functions
|
|
bool compare_exchange_weak(_Tp& _expected, _Tp _desired, mem_ord _success, mem_ord _failure)
|
|
{
|
|
return fvalue.compare_exchange_weak(_expected, _desired, _success, _failure);
|
|
}
|
|
bool compare_exchange_weak(_Tp& _expected, _Tp _desired, mem_ord _success,
|
|
mem_ord _failure) volatile
|
|
{
|
|
return fvalue.compare_exchange_weak(_expected, _desired, _success, _failure);
|
|
}
|
|
|
|
bool compare_exchange_weak(_Tp& _expected, _Tp _desired, mem_ord _order)
|
|
{
|
|
return fvalue.compare_exchange_weak(_expected, _desired, _order);
|
|
}
|
|
bool compare_exchange_weak(_Tp& _expected, _Tp _desired, mem_ord _order) volatile
|
|
{
|
|
return fvalue.compare_exchange_weak(_expected, _desired, _order);
|
|
}
|
|
|
|
bool compare_exchange_strong(_Tp& _expected, _Tp _desired, mem_ord _success, mem_ord _failure)
|
|
{
|
|
return fvalue.compare_exchange_weak(_expected, _desired, _success, _failure);
|
|
}
|
|
bool compare_exchange_strong(_Tp& _expected, _Tp _desired, mem_ord _success,
|
|
mem_ord _failure) volatile
|
|
{
|
|
return fvalue.compare_exchange_weak(_expected, _desired, _success, _failure);
|
|
}
|
|
|
|
bool compare_exchange_strong(_Tp& _expected, _Tp _desired, mem_ord _order)
|
|
{
|
|
return fvalue.compare_exchange_weak(_expected, _desired, _order);
|
|
}
|
|
bool compare_exchange_strong(_Tp& _expected, _Tp _desired, mem_ord _order) volatile
|
|
{
|
|
return fvalue.compare_exchange_weak(_expected, _desired, _order);
|
|
}
|
|
|
|
// value_type operators
|
|
G4atomic& operator+=(const value_type& rhs)
|
|
{
|
|
atomics::increment(&fvalue, rhs, fMemOrder);
|
|
return *this;
|
|
}
|
|
G4atomic& operator-=(const value_type& rhs)
|
|
{
|
|
atomics::decrement(&fvalue, rhs, fMemOrder);
|
|
return *this;
|
|
}
|
|
G4atomic& operator*=(const value_type& rhs)
|
|
{
|
|
atomics::multiply(&fvalue, rhs, fMemOrder);
|
|
return *this;
|
|
}
|
|
G4atomic& operator/=(const value_type& rhs)
|
|
{
|
|
atomics::divide(&fvalue, rhs, fMemOrder);
|
|
return *this;
|
|
}
|
|
|
|
// atomic operators
|
|
G4atomic& operator+=(const G4atomic& rhs)
|
|
{
|
|
atomics::increment(&fvalue, rhs.fvalue);
|
|
return *this;
|
|
}
|
|
G4atomic& operator-=(const G4atomic& rhs)
|
|
{
|
|
atomics::decrement(&fvalue, rhs.fvalue);
|
|
return *this;
|
|
}
|
|
G4atomic& operator*=(const G4atomic& rhs)
|
|
{
|
|
atomics::multiply(&fvalue, rhs.fvalue);
|
|
return *this;
|
|
}
|
|
G4atomic& operator/=(const G4atomic& rhs)
|
|
{
|
|
atomics::divide(&fvalue, rhs.fvalue);
|
|
return *this;
|
|
}
|
|
|
|
G4atomic& operator+=(const G4atomic& rhs) volatile
|
|
{
|
|
atomics::increment(&fvalue, rhs.fvalue);
|
|
return *this;
|
|
}
|
|
G4atomic& operator-=(const G4atomic& rhs) volatile
|
|
{
|
|
atomics::decrement(&fvalue, rhs.fvalue);
|
|
return *this;
|
|
}
|
|
G4atomic& operator*=(const G4atomic& rhs) volatile
|
|
{
|
|
atomics::multiply(&fvalue, rhs.fvalue);
|
|
return *this;
|
|
}
|
|
G4atomic& operator/=(const G4atomic& rhs) volatile
|
|
{
|
|
atomics::divide(&fvalue, rhs.fvalue);
|
|
return *this;
|
|
}
|
|
|
|
// STL atomic operators
|
|
G4atomic& operator+=(const std::atomic<_Tp>& rhs)
|
|
{
|
|
atomics::increment(&fvalue, rhs, fMemOrder);
|
|
return *this;
|
|
}
|
|
G4atomic& operator-=(const std::atomic<_Tp>& rhs)
|
|
{
|
|
atomics::decrement(&fvalue, rhs, fMemOrder);
|
|
return *this;
|
|
}
|
|
G4atomic& operator*=(const std::atomic<_Tp>& rhs)
|
|
{
|
|
atomics::multiply(&fvalue, rhs, fMemOrder);
|
|
return *this;
|
|
}
|
|
G4atomic& operator/=(const std::atomic<_Tp>& rhs)
|
|
{
|
|
atomics::divide(&fvalue, rhs, fMemOrder);
|
|
return *this;
|
|
}
|
|
|
|
G4atomic& operator+=(const std::atomic<_Tp>& rhs) volatile
|
|
{
|
|
atomics::increment(&fvalue, rhs, fMemOrder);
|
|
return *this;
|
|
}
|
|
G4atomic& operator-=(const std::atomic<_Tp>& rhs) volatile
|
|
{
|
|
atomics::decrement(&fvalue, rhs, fMemOrder);
|
|
return *this;
|
|
}
|
|
G4atomic& operator*=(const std::atomic<_Tp>& rhs) volatile
|
|
{
|
|
atomics::multiply(&fvalue, rhs, fMemOrder);
|
|
return *this;
|
|
}
|
|
G4atomic& operator/=(const std::atomic<_Tp>& rhs) volatile
|
|
{
|
|
atomics::divide(&fvalue, rhs, fMemOrder);
|
|
return *this;
|
|
}
|
|
|
|
// increment operators
|
|
value_type operator++()
|
|
{
|
|
value_type _tmp = ++fvalue;
|
|
return _tmp;
|
|
}
|
|
value_type operator++(int)
|
|
{
|
|
value_type _tmp = fvalue++;
|
|
return _tmp;
|
|
}
|
|
|
|
value_type operator--()
|
|
{
|
|
value_type _tmp = --fvalue;
|
|
return _tmp;
|
|
}
|
|
value_type operator--(int)
|
|
{
|
|
value_type _tmp = fvalue--;
|
|
return _tmp;
|
|
}
|
|
|
|
protected:
|
|
base_type fvalue;
|
|
mem_ord fMemOrder;
|
|
};
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
#else // ! G4MULTITHREADED
|
|
|
|
template<typename _Tp>
|
|
using G4atomic = _Tp;
|
|
|
|
#endif // G4MULTITHREADED
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
#endif // G4atomic_hh_
|