eathread_atomic_cpp11.h 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Electronic Arts Inc. All rights reserved.
  3. ///////////////////////////////////////////////////////////////////////////////
  4. #if defined(EA_PRAGMA_ONCE_SUPPORTED)
  5. #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
  6. #endif
  7. #ifndef EATHREAD_ATOMIC_CPP11_H
  8. #define EATHREAD_ATOMIC_CPP11_H
  9. EA_DISABLE_VC_WARNING(4265 4365 4836 4571 4625 4626 4628 4193 4127 4548 4574 4731)
  10. #include <atomic>
  11. EA_RESTORE_VC_WARNING()
  12. namespace EA
  13. {
  14. namespace Thread
  15. {
  16. #define EA_THREAD_ATOMIC_IMPLEMENTED
  17. /// Non-member atomic functions
  18. /// These act the same as the class functions below.
  19. /// The T return values are the new value, except for the AtomicSwap function which returns the swapped out value.
  20. ///
  21. /// todo: Implement me when we have a platform to test this on. C++11 atomics are disabled on all platforms.
  22. ///
  23. template <class T>
  24. class EATHREADLIB_API AtomicInt
  25. {
  26. public:
  27. typedef AtomicInt<T> ThisType;
  28. typedef T ValueType;
  29. /// AtomicInt
  30. /// Empty constructor. Intentionally leaves mValue in an unspecified state.
  31. /// This is done so that an AtomicInt acts like a standard built-in integer.
  32. AtomicInt() {}
  33. /// AtomicInt
  34. /// Constructs with an intial value.
  35. AtomicInt(ValueType n) : mValue(n) {}
  36. /// AtomicInt
  37. /// Copy ctor. Uses GetValue to read the value, and thus is synchronized.
  38. AtomicInt(const ThisType& x) : mValue(x.GetValue()) {}
  39. /// AtomicInt
  40. /// Assignment operator. Uses GetValue to read the value, and thus is synchronized.
  41. AtomicInt& operator=(const ThisType& x)
  42. { mValue = x.GetValue(); return *this; }
  43. /// GetValue
  44. /// Safely gets the current value. A platform-specific version of
  45. /// this might need to do something more than just read the value.
  46. ValueType GetValue() const volatile { return mValue; }
  47. /// GetValueRaw
  48. /// "Unsafely" gets the current value. This is useful for algorithms
  49. /// that want to poll the value in a high performance way before
  50. /// reading or setting the value in a more costly thread-safe way.
  51. /// You should not use this function when attempting to do thread-safe
  52. /// atomic operations.
  53. ValueType GetValueRaw() const { return mValue; }
  54. /// SetValue
  55. /// Safely sets a new value. Returns the old value. Note that due to
  56. /// expected multithreaded accesses, a call to GetValue after SetValue
  57. /// might return a different value then what was set with SetValue.
  58. /// This of course depends on your situation.
  59. ValueType SetValue(ValueType n) { return mValue.exchange(n); }
  60. /// SetValueConditional
  61. /// Safely the value to a new value if the original value is equal to
  62. /// a condition value. Returns true if the condition was met and the
  63. /// assignment occurred. The comparison and value setting are done as
  64. /// an atomic operation and thus another thread cannot intervene between
  65. /// the two as would be the case with simple C code.
  66. bool SetValueConditional(ValueType n, ValueType condition)
  67. {
  68. return mValue.compare_exchange_strong(condition, n);
  69. }
  70. /// Increment
  71. /// Safely increments the value. Returns the new value.
  72. /// This function acts the same as the C++ pre-increment operator.
  73. ValueType Increment() { return ++mValue; }
  74. /// Decrement
  75. /// Safely decrements the value. Returns the new value.
  76. /// This function acts the same as the C++ pre-decrement operator.
  77. ValueType Decrement() { return --mValue; }
  78. /// Add
  79. /// Safely adds a value, which can be negative. Returns the new value.
  80. /// You can implement subtraction with this function by using a negative argument.
  81. ValueType Add(ValueType n) { return (mValue += n); }
  82. /// operators
  83. /// These allow an AtomicInt object to safely act like a built-in type.
  84. ///
  85. /// Note: The operators for AtomicInt behaves differently than standard
  86. /// C++ operators in that it will always return a ValueType instead
  87. /// of a reference.
  88. ///
  89. /// cast operator
  90. /// Returns the AtomicInt value as an integral type. This allows the
  91. /// AtomicInt to behave like a standard built-in integer type.
  92. operator const ValueType() const { return mValue; }
  93. /// operator =
  94. /// Assigns a new value and returns the value after the operation.
  95. ///
  96. ValueType operator=(ValueType n) { SetValue(n); return n; }
  97. /// pre-increment operator+=
  98. /// Adds a value to the AtomicInt and returns the value after the operation.
  99. ///
  100. /// This function doesn't obey the C++ standard in that it does not return
  101. /// a reference, but rather the value of the AtomicInt after the
  102. /// operation is complete. It must be noted that this design is motivated by
  103. /// the fact that it is unsafe to rely on the returned value being equal to
  104. /// the previous value + n, as another thread might have modified the AtomicInt
  105. /// immediately after the subtraction operation. So rather than returning the
  106. /// reference of AtomicInt, the function returns a copy of the AtomicInt value
  107. /// used in the function.
  108. ValueType operator+=(ValueType n) { mValue += n; return mValue; }
  109. /// pre-increment operator-=
  110. /// Subtracts a value to the AtomicInt and returns the value after the operation.
  111. ///
  112. /// This function doesn't obey the C++ standard in that it does not return
  113. // a reference, but rather the value of the AtomicInt after the
  114. /// operation is complete. It must be noted that this design is motivated by
  115. /// the fact that it is unsafe to rely on the returned value being equal to
  116. /// the previous value - n, as another thread might have modified the AtomicInt
  117. /// immediately after the subtraction operation. So rather than returning the
  118. /// reference of AtomicInt, the function returns a copy of the AtomicInt value
  119. /// used in the function.
  120. ValueType operator-=(ValueType n) { mValue -= n; return mValue; }
  121. /// pre-increment operator++
  122. /// Increments the AtomicInt.
  123. ///
  124. /// This function doesn't obey the C++ standard in that it does not return
  125. // a reference, but rather the value of the AtomicInt after the
  126. /// operation is complete. It must be noted that this design is motivated by
  127. /// the fact that it is unsafe to rely on the returned value being equal to
  128. /// the previous value + 1, as another thread might have modified the AtomicInt
  129. /// immediately after the subtraction operation. So rather than returning the
  130. /// reference of AtomicInt, the function returns a copy of the AtomicInt value
  131. /// used in the function.
  132. ValueType operator++() { return ++mValue; }
  133. /// post-increment operator++
  134. /// Increments the AtomicInt and returns the value of the AtomicInt before
  135. /// the increment operation.
  136. ///
  137. /// This function doesn't obey the C++ standard in that it does not return
  138. // a reference, but rather the value of the AtomicInt after the
  139. /// operation is complete. It must be noted that this design is motivated by
  140. /// the fact that it is unsafe to rely on the returned value being equal to
  141. /// the previous value, as another thread might have modified the AtomicInt
  142. /// immediately after the subtraction operation. So rather than returning the
  143. /// reference of AtomicInt, the function returns a copy of the AtomicInt value
  144. /// used in the function.
  145. ValueType operator++(int) { return mValue++; }
  146. /// pre-increment operator--
  147. /// Decrements the AtomicInt.
  148. ///
  149. /// This function doesn't obey the C++ standard in that it does not return
  150. // a reference, but rather the value of the AtomicInt after the
  151. /// operation is complete. It must be noted that this design is motivated by
  152. /// the fact that it is unsafe to rely on the returned value being equal to
  153. /// the previous value - 1, as another thread might have modified the AtomicInt
  154. /// immediately after the subtraction operation. So rather than returning the
  155. /// reference of AtomicInt, the function returns a copy of the AtomicInt value
  156. /// used in the function.
  157. ValueType operator--() { return --mValue; }
  158. /// post-increment operator--
  159. /// Increments the AtomicInt and returns the value of the AtomicInt before
  160. /// the increment operation.
  161. ///
  162. /// This function doesn't obey the C++ standard in that it does not return
  163. // a reference, but rather the value of the AtomicInt after the
  164. /// operation is complete. It must be noted that this design is motivated by
  165. /// the fact that it is unsafe to rely on the returned value being equal to
  166. /// the previous value, as another thread might have modified the AtomicInt
  167. /// immediately after the subtraction operation. So rather than returning the
  168. /// reference of AtomicInt, the function returns a copy of the AtomicInt value
  169. /// used in the function.
  170. ValueType operator--(int) { return mValue--;}
  171. private:
  172. std::atomic<T> mValue;
  173. };
  174. }
  175. }
  176. #endif // EATHREAD_ATOMIC_CPP11_H