You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

161 lines
2.5 KiB

  1. #pragma once
  2. #include <condition_variable>
  3. #include <mutex>
  4. #include <queue>
  5. #include <utility>
  6. template<typename T>
  7. class UnboundedQueue
  8. {
  9. public:
  10. explicit
  11. UnboundedQueue(bool block_ = true)
  12. : _block(block_)
  13. {
  14. }
  15. void
  16. push(const T& item_)
  17. {
  18. {
  19. std::lock_guard<std::mutex> guard(_queue_lock);
  20. _queue.push(item_);
  21. }
  22. _condition.notify_one();
  23. }
  24. void
  25. push(T&& item_)
  26. {
  27. {
  28. std::lock_guard<std::mutex> guard(_queue_lock);
  29. _queue.push(std::move(item_));
  30. }
  31. _condition.notify_one();
  32. }
  33. template<typename... Args>
  34. void
  35. emplace(Args&&... args_)
  36. {
  37. {
  38. std::lock_guard<std::mutex> guard(_queue_lock);
  39. _queue.emplace(std::forward<Args>(args_)...);
  40. }
  41. _condition.notify_one();
  42. }
  43. bool
  44. try_push(const T& item_)
  45. {
  46. {
  47. std::unique_lock<std::mutex> lock(_queue_lock, std::try_to_lock);
  48. if(!lock)
  49. return false;
  50. _queue.push(item_);
  51. }
  52. _condition.notify_one();
  53. return true;
  54. }
  55. bool
  56. try_push(T&& item_)
  57. {
  58. {
  59. std::unique_lock<std::mutex> lock(_queue_lock, std::try_to_lock);
  60. if(!lock)
  61. return false;
  62. _queue.push(std::move(item_));
  63. }
  64. _condition.notify_one();
  65. return true;
  66. }
  67. //TODO: push multiple T at once
  68. bool
  69. pop(T& item_)
  70. {
  71. std::unique_lock<std::mutex> guard(_queue_lock);
  72. _condition.wait(guard, [&]() { return !_queue.empty() || !_block; });
  73. if(_queue.empty())
  74. return false;
  75. item_ = std::move(_queue.front());
  76. _queue.pop();
  77. return true;
  78. }
  79. bool
  80. try_pop(T& item_)
  81. {
  82. std::unique_lock<std::mutex> lock(_queue_lock, std::try_to_lock);
  83. if(!lock || _queue.empty())
  84. return false;
  85. item_ = std::move(_queue.front());
  86. _queue.pop();
  87. return true;
  88. }
  89. std::size_t
  90. size() const
  91. {
  92. std::lock_guard<std::mutex> guard(_queue_lock);
  93. return _queue.size();
  94. }
  95. bool
  96. empty() const
  97. {
  98. std::lock_guard<std::mutex> guard(_queue_lock);
  99. return _queue.empty();
  100. }
  101. void
  102. block()
  103. {
  104. std::lock_guard<std::mutex> guard(_queue_lock);
  105. _block = true;
  106. }
  107. void
  108. unblock()
  109. {
  110. {
  111. std::lock_guard<std::mutex> guard(_queue_lock);
  112. _block = false;
  113. }
  114. _condition.notify_all();
  115. }
  116. bool
  117. blocking() const
  118. {
  119. std::lock_guard<std::mutex> guard(_queue_lock);
  120. return _block;
  121. }
  122. private:
  123. mutable std::mutex _queue_lock;
  124. private:
  125. bool _block;
  126. std::queue<T> _queue;
  127. std::condition_variable _condition;
  128. };