Atomic.h 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #pragma once
  6. #include <AnKi/Util/StdTypes.h>
  7. #include <atomic>
  8. namespace anki {
  9. /// @addtogroup util_other
  10. /// @{
  11. using StdMemoryOrderEnumUnderlyingType = std::underlying_type_t<std::memory_order>;
  12. enum class AtomicMemoryOrder : StdMemoryOrderEnumUnderlyingType
  13. {
  14. kRelaxed = StdMemoryOrderEnumUnderlyingType(std::memory_order_relaxed),
  15. kConsume = StdMemoryOrderEnumUnderlyingType(std::memory_order_consume),
  16. kAcquire = StdMemoryOrderEnumUnderlyingType(std::memory_order_acquire),
  17. kRelease = StdMemoryOrderEnumUnderlyingType(std::memory_order_release),
  18. kAcqRel = StdMemoryOrderEnumUnderlyingType(std::memory_order_acq_rel),
  19. kSeqCst = StdMemoryOrderEnumUnderlyingType(std::memory_order_seq_cst)
  20. };
  21. /// Atomic template. At the moment it doesn't work well with pointers.
  22. template<typename T, AtomicMemoryOrder kMemOrder = AtomicMemoryOrder::kRelaxed>
  23. class Atomic
  24. {
  25. public:
  26. using Value = T;
  27. static constexpr AtomicMemoryOrder kDefaultMemoryOrder = kMemOrder;
  28. /// It will not set itself to zero.
  29. Atomic()
  30. {
  31. }
  32. Atomic(Value a)
  33. : m_val(a)
  34. {
  35. }
  36. Atomic(const Atomic&) = delete; // Non-copyable
  37. Atomic& operator=(const Atomic&) = delete; // Non-copyable
  38. /// Set the value without protection.
  39. void setNonAtomically(Value a)
  40. {
  41. m_val = a;
  42. }
  43. /// Get the value without protection.
  44. Value getNonAtomically() const
  45. {
  46. return m_val;
  47. }
  48. /// Get the value of the atomic.
  49. Value load(AtomicMemoryOrder memOrd = kDefaultMemoryOrder) const
  50. {
  51. return m_att.load(std::memory_order(memOrd));
  52. }
  53. /// Store
  54. void store(Value a, AtomicMemoryOrder memOrd = kDefaultMemoryOrder)
  55. {
  56. m_att.store(a, std::memory_order(memOrd));
  57. }
  58. /// Fetch and add.
  59. template<typename Y>
  60. Value fetchAdd(Y a, AtomicMemoryOrder memOrd = kDefaultMemoryOrder)
  61. {
  62. return m_att.fetch_add(a, std::memory_order(memOrd));
  63. }
  64. /// Fetch and subtract.
  65. template<typename Y>
  66. Value fetchSub(Y a, AtomicMemoryOrder memOrd = kDefaultMemoryOrder)
  67. {
  68. return m_att.fetch_sub(a, std::memory_order(memOrd));
  69. }
  70. /// Fetch and do bitwise or.
  71. template<typename Y>
  72. Value fetchOr(Y a, AtomicMemoryOrder memOrd = kDefaultMemoryOrder)
  73. {
  74. return m_att.fetch_or(a, std::memory_order(memOrd));
  75. }
  76. /// Fetch and do bitwise and.
  77. template<typename Y>
  78. Value fetchAnd(Y a, AtomicMemoryOrder memOrd = kDefaultMemoryOrder)
  79. {
  80. return m_att.fetch_and(a, std::memory_order(memOrd));
  81. }
  82. /// @code
  83. /// if(m_val == expected) {
  84. /// m_val = desired;
  85. /// return true;
  86. /// } else {
  87. /// expected = m_val;
  88. /// return false;
  89. /// }
  90. /// @endcode
  91. Bool compareExchange(Value& expected, Value desired, AtomicMemoryOrder successMemOrd = kDefaultMemoryOrder,
  92. AtomicMemoryOrder failMemOrd = kDefaultMemoryOrder)
  93. {
  94. return m_att.compare_exchange_weak(expected, desired, std::memory_order(successMemOrd), std::memory_order(failMemOrd));
  95. }
  96. /// Set @a a to the atomic and return the previous value.
  97. Value exchange(Value a, AtomicMemoryOrder memOrd = kDefaultMemoryOrder)
  98. {
  99. return m_att.exchange(a, std::memory_order(memOrd));
  100. }
  101. /// Store the minimum using compare-and-swap.
  102. void min(Value a)
  103. {
  104. Value prev = load();
  105. while(a < prev && !compareExchange(prev, a))
  106. {
  107. }
  108. }
  109. /// Store the maximum using compare-and-swap.
  110. void max(Value a)
  111. {
  112. Value prev = load();
  113. while(a > prev && !compareExchange(prev, a))
  114. {
  115. }
  116. }
  117. private:
  118. union
  119. {
  120. Value m_val;
  121. std::atomic<Value> m_att;
  122. };
  123. };
  124. /// @}
  125. } // end namespace anki