ring_buffer_with_spin_lock.h 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. #pragma once
  2. #include "ring_buffer.h"
  3. #include <library/cpp/deprecated/atomic/atomic.h>
  4. #include <util/system/spinlock.h>
  5. template <typename T>
  6. class TRingBufferWithSpinLock {
  7. private:
  8. TRingBuffer<T> RingBuffer;
  9. TSpinLock SpinLock;
  10. TAtomic CachedSize;
  11. public:
  12. TRingBufferWithSpinLock()
  13. : CachedSize(0)
  14. {
  15. }
  16. void Push(const T& t) {
  17. PushAll(t);
  18. }
  19. void PushAll(TArrayRef<const T> collection) {
  20. if (collection.empty()) {
  21. return;
  22. }
  23. TGuard<TSpinLock> Guard(SpinLock);
  24. RingBuffer.PushAll(collection);
  25. AtomicSet(CachedSize, RingBuffer.Size());
  26. }
  27. bool TryPop(T* r, size_t* sizePtr = nullptr) {
  28. if (AtomicGet(CachedSize) == 0) {
  29. return false;
  30. }
  31. bool ok;
  32. size_t size;
  33. {
  34. TGuard<TSpinLock> Guard(SpinLock);
  35. ok = RingBuffer.TryPop(r);
  36. size = RingBuffer.Size();
  37. AtomicSet(CachedSize, size);
  38. }
  39. if (!!sizePtr) {
  40. *sizePtr = size;
  41. }
  42. return ok;
  43. }
  44. TMaybe<T> TryPop() {
  45. T tmp;
  46. if (TryPop(&tmp)) {
  47. return tmp;
  48. } else {
  49. return TMaybe<T>();
  50. }
  51. }
  52. bool PushAllAndTryPop(TArrayRef<const T> collection, T* r) {
  53. if (collection.size() == 0) {
  54. return TryPop(r);
  55. } else {
  56. if (AtomicGet(CachedSize) == 0) {
  57. *r = collection[0];
  58. if (collection.size() > 1) {
  59. TGuard<TSpinLock> guard(SpinLock);
  60. RingBuffer.PushAll(MakeArrayRef(collection.data() + 1, collection.size() - 1));
  61. AtomicSet(CachedSize, RingBuffer.Size());
  62. }
  63. } else {
  64. TGuard<TSpinLock> guard(SpinLock);
  65. RingBuffer.PushAll(collection);
  66. *r = RingBuffer.Pop();
  67. AtomicSet(CachedSize, RingBuffer.Size());
  68. }
  69. return true;
  70. }
  71. }
  72. bool Empty() const {
  73. return AtomicGet(CachedSize) == 0;
  74. }
  75. size_t Size() const {
  76. TGuard<TSpinLock> Guard(SpinLock);
  77. return RingBuffer.Size();
  78. }
  79. };