|
||||
File indexing completed on 2025-01-30 10:06:46
0001 //FJSTARTHEADER 0002 // $Id$ 0003 // 0004 // Copyright (c) 2014-2021, Matteo Cacciari, Gavin P. Salam and Gregory Soyez 0005 // 0006 //---------------------------------------------------------------------- 0007 // This file is part of FastJet. 0008 // 0009 // FastJet is free software; you can redistribute it and/or modify 0010 // it under the terms of the GNU General Public License as published by 0011 // the Free Software Foundation; either version 2 of the License, or 0012 // (at your option) any later version. 0013 // 0014 // The algorithms that underlie FastJet have required considerable 0015 // development. They are described in the original FastJet paper, 0016 // hep-ph/0512210 and in the manual, arXiv:1111.6097. If you use 0017 // FastJet as part of work towards a scientific publication, please 0018 // quote the version you use and include a citation to the manual and 0019 // optionally also to hep-ph/0512210. 0020 // 0021 // FastJet is distributed in the hope that it will be useful, 0022 // but WITHOUT ANY WARRANTY; without even the implied warranty of 0023 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0024 // GNU General Public License for more details. 0025 // 0026 // You should have received a copy of the GNU General Public License 0027 // along with FastJet. If not, see <http://www.gnu.org/licenses/>. 0028 //---------------------------------------------------------------------- 0029 //FJENDHEADER 0030 0031 #ifndef __FASTJET_THREAD_SAFETY_HELPERS_HH__ 0032 #define __FASTJET_THREAD_SAFETY_HELPERS_HH__ 0033 0034 /// The code in this file is supposed to help writing code that will 0035 /// automatically provide thread-safe features when available and come 0036 /// revert back to "old/standard" C++ if thread-safety is not switched 0037 /// on 0038 /// 0039 ///\TODO fix doxygen comments (declare things as internal; make sure 0040 /// doxygen doc is not duplicate --- if necessary, keep only doxygen 0041 /// comments in the thread-safe versions) 0042 0043 #include "fastjet/internal/base.hh" 0044 #include "fastjet/config.h" 0045 #include <limits> 0046 0047 #ifdef FASTJET_HAVE_LIMITED_THREAD_SAFETY 0048 0049 // introduces a few tools in CXX11 that we'll use in some FJ classes 0050 #include <atomic> 0051 0052 FASTJET_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh 0053 0054 namespace thread_safety_helpers{ 0055 0056 //---------------------------------------------------------------------- 0057 /// \if internal_doc 0058 /// \class AtomicCounter 0059 /// 0060 /// provides a thread-safe counter which can only step one unit at a time 0061 /// and has overflow protection 0062 /// \endif 0063 template<typename T> 0064 class AtomicCounter{ 0065 public: 0066 /// default ctor 0067 AtomicCounter() : _count{0}{} 0068 0069 /// ctor with initialisation 0070 AtomicCounter(const T &count) : _count{count}{} 0071 0072 /// copy ctor (works around the deleted copy in atomic, see 0073 /// e.g. http://stackoverflow.com/questions/19883092/error-implicitly-deleted-because-the-default-definition-would-be-ill-formed-ve) 0074 AtomicCounter(const AtomicCounter &other) : _count{other._count.load()}{} 0075 0076 /// for a more friendly usage, overload the type cast to the 0077 /// base template type 0078 operator T() const{ return _count.load();} 0079 0080 /// get the count 0081 T get() const{ return _count.load();} 0082 0083 /// set the counter to a given value 0084 void set(const T new_value){ 0085 _count.store(new_value); 0086 } 0087 0088 /// step the counter and return the count just before it was stepped 0089 /// 0090 /// Q: can we declare this as T && ...? 0091 T step(){ 0092 // another thread could be upadting this at the same time, so extra 0093 // care is needed. 0094 // 0095 // Recall that the compare_exchange_strong will return true if the 0096 // exchange has been done. Otherwise, it means that the count 0097 // changed in the meantime, so we try again. Also, since when it 0098 // "fails" compare_exchange_strong loads the count of *this in 0099 // expected, count does not need to be re-read in the loop! 0100 // 0101 // Note that at the end of this procedure, count will countain the 0102 // number of times this warning occured just before this 0103 // occurence. It can thus be used to see if it needs to be printed 0104 // out 0105 // 0106 // Note also that compared to the apparently simpler fetch_add, 0107 // this method also avoids overflows 0108 T count = _count; 0109 while (_count < std::numeric_limits<T>::max() 0110 && !(_count.compare_exchange_strong(count, count+1))); 0111 return count; 0112 } 0113 0114 /// override the ++ operator 0115 /// prefix version 0116 inline T operator++(){ 0117 return step()+1; 0118 } 0119 0120 /// override the ++ operator 0121 /// postfix version 0122 inline T operator++(int){ 0123 return step(); 0124 } 0125 0126 private: 0127 std::atomic<T> _count; ///< the actual count 0128 }; 0129 0130 //---------------------------------------------------------------------- 0131 /// \if internal_doc 0132 /// \class FirstTimeTrue 0133 /// provides an object wich will return "true" the first time () is 0134 /// called and false afterwards 0135 /// \endif 0136 class FirstTimeTrue{ 0137 public: 0138 FirstTimeTrue(): _first_time{true}{} 0139 // explicit copy ctor (this class contains atimoc vars) 0140 FirstTimeTrue(const FirstTimeTrue &other) : _first_time{other._first_time.load()}{} 0141 bool operator()(){ 0142 // Thread-safety note: 0143 // the construct 0144 // if (!_first_time) {return;} 0145 // _first_time = false; 0146 // is dangerous because the test can be passed by a second thread 0147 // before the first one has set it to false. Use atomic exchange 0148 // to handle this better 0149 bool expected = true; 0150 // this behaves as follows: if we have the expected value (true), 0151 // set _first_time to the desired (false) and return 0152 // true. Otherwise, do nothing and return false 0153 // 0154 // Note that since we are not using the "expected" value 0155 // afterwards, we can use a relaxed memory ordering if the next 0156 // call returns false 0157 return _first_time.compare_exchange_strong(expected, false, 0158 std::memory_order_seq_cst, 0159 std::memory_order_relaxed); 0160 } 0161 private: 0162 std::atomic<bool> _first_time; 0163 }; 0164 0165 } // namespace thread_safety_helpers 0166 0167 FASTJET_END_NAMESPACE 0168 0169 #else // FJ wo thread-safety features 0170 0171 FASTJET_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh 0172 0173 namespace thread_safety_helpers{ 0174 //---------------------------------------------------------------------- 0175 /// \class AtomicCounter 0176 /// 0177 /// (would) provides a thread-safe counter (with CXX11 features) 0178 template<typename T> 0179 class AtomicCounter{ 0180 public: 0181 /// default ctor 0182 AtomicCounter() : _count(0){} 0183 0184 /// ctor with initialisation 0185 AtomicCounter(const T &count) : _count(count){} 0186 0187 /// copy ctor 0188 AtomicCounter(const AtomicCounter &other) : _count(other._count){} 0189 0190 /// for a more friendly usage, overload the type cast 0191 /// 0192 /// This will (likely) allow a transparent usage w or wo C++11 0193 /// features enabled 0194 operator T() const{ return _count;} 0195 0196 /// get the count 0197 T get() const{ return _count;} 0198 0199 /// set the counter to a given value 0200 void set(const T new_value){ 0201 _count = new_value; 0202 } 0203 0204 /// step the counter and return the value just before it was stepped 0205 T step(){ 0206 unsigned int count = _count; 0207 if (_count < std::numeric_limits<T>::max()){ _count++; } 0208 return count; 0209 } 0210 0211 /// override the ++ operator 0212 /// prefix version 0213 inline T operator++(){ 0214 return step()+1; 0215 } 0216 0217 /// override the ++ operator 0218 /// postfix version 0219 inline T operator++(int){ 0220 return step(); 0221 } 0222 0223 private: 0224 T _count; ///< the actual value 0225 }; 0226 0227 //---------------------------------------------------------------------- 0228 /// \class FirstTimeTrue 0229 /// provides an object wich will return "true" the first time () is 0230 /// called and false afterwards 0231 class FirstTimeTrue{ 0232 public: 0233 FirstTimeTrue(): _first_time(true){} 0234 bool operator()(){ 0235 if (!_first_time) {return false;} 0236 _first_time = false; 0237 return true; 0238 } 0239 private: 0240 bool _first_time; 0241 }; 0242 } // namespace thread_safety_helpers 0243 0244 FASTJET_END_NAMESPACE 0245 0246 0247 0248 #endif // FASTJET_HAVE_LIMITED_THREAD_SAFETY 0249 0250 #endif // __FASTJET_THREAD_SAFETY_HELPERS_HH__
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |