refcount.h 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. #pragma once
  2. #include <util/system/guard.h>
  3. #include <util/system/defaults.h>
  4. #include <util/system/yassert.h>
  5. #include <atomic>
  6. template <class TCounterCheckPolicy>
  7. class TSimpleCounterTemplate: public TCounterCheckPolicy {
  8. using TCounterCheckPolicy::Check;
  9. public:
  10. inline TSimpleCounterTemplate(long initial = 0) noexcept
  11. : Counter_(initial)
  12. {
  13. }
  14. inline ~TSimpleCounterTemplate() {
  15. Check();
  16. }
  17. inline intptr_t Add(intptr_t d) noexcept {
  18. Check();
  19. return Counter_ += d;
  20. }
  21. inline intptr_t Inc() noexcept {
  22. return Add(1);
  23. }
  24. inline intptr_t Sub(intptr_t d) noexcept {
  25. Check();
  26. return Counter_ -= d;
  27. }
  28. inline intptr_t Dec() noexcept {
  29. return Sub(1);
  30. }
  31. inline bool TryWeakInc() noexcept {
  32. if (!Counter_) {
  33. return false;
  34. }
  35. Inc();
  36. Y_ASSERT(Counter_ != 0);
  37. return true;
  38. }
  39. inline intptr_t Val() const noexcept {
  40. return Counter_;
  41. }
  42. private:
  43. intptr_t Counter_;
  44. };
  45. class TNoCheckPolicy {
  46. protected:
  47. inline void Check() const {
  48. }
  49. };
  50. #if defined(SIMPLE_COUNTER_THREAD_CHECK)
  51. #include <util/system/thread.i>
  52. class TCheckPolicy {
  53. public:
  54. inline TCheckPolicy() {
  55. ThreadId = SystemCurrentThreadId();
  56. }
  57. protected:
  58. inline void Check() const {
  59. Y_ABORT_UNLESS(ThreadId == SystemCurrentThreadId(), "incorrect usage of TSimpleCounter");
  60. }
  61. private:
  62. size_t ThreadId;
  63. };
  64. #else
  65. using TCheckPolicy = TNoCheckPolicy;
  66. #endif
  67. // Use this one if access from multiple threads to your pointer is an error and you want to enforce thread checks
  68. using TSimpleCounter = TSimpleCounterTemplate<TCheckPolicy>;
  69. // Use this one if you do want to share the pointer between threads, omit thread checks and do the synchronization yourself
  70. using TExplicitSimpleCounter = TSimpleCounterTemplate<TNoCheckPolicy>;
  71. template <class TCounterCheckPolicy>
  72. struct TCommonLockOps<TSimpleCounterTemplate<TCounterCheckPolicy>> {
  73. static inline void Acquire(TSimpleCounterTemplate<TCounterCheckPolicy>* t) noexcept {
  74. t->Inc();
  75. }
  76. static inline void Release(TSimpleCounterTemplate<TCounterCheckPolicy>* t) noexcept {
  77. t->Dec();
  78. }
  79. };
  80. class TAtomicCounter {
  81. public:
  82. inline TAtomicCounter(long initial = 0) noexcept
  83. : Counter_(initial)
  84. {
  85. }
  86. TAtomicCounter(const TAtomicCounter& other)
  87. : Counter_(other.Counter_.load())
  88. {
  89. }
  90. TAtomicCounter& operator=(const TAtomicCounter& other) {
  91. Counter_.store(other.Counter_.load());
  92. return *this;
  93. }
  94. inline ~TAtomicCounter() = default;
  95. inline intptr_t Add(intptr_t d) noexcept {
  96. return Counter_ += d;
  97. }
  98. inline intptr_t Inc() noexcept {
  99. return Add(1);
  100. }
  101. inline intptr_t Sub(intptr_t d) noexcept {
  102. return Counter_ -= d;
  103. }
  104. inline intptr_t Dec() noexcept {
  105. return Sub(1);
  106. }
  107. inline intptr_t Val() const noexcept {
  108. return Counter_.load();
  109. }
  110. inline bool TryWeakInc() noexcept {
  111. for (auto curValue = Counter_.load(std::memory_order_acquire);;) {
  112. if (!curValue) {
  113. return false;
  114. }
  115. if (Counter_.compare_exchange_weak(curValue, curValue + 1)) {
  116. return true;
  117. }
  118. }
  119. }
  120. private:
  121. std::atomic<intptr_t> Counter_;
  122. };
  123. template <>
  124. struct TCommonLockOps<TAtomicCounter> {
  125. static inline void Acquire(TAtomicCounter* t) noexcept {
  126. t->Inc();
  127. }
  128. static inline void Release(TAtomicCounter* t) noexcept {
  129. t->Dec();
  130. }
  131. };