RingQueue.hpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. #ifndef RINGQUEUE_H
  2. #define RINGQUEUE_H
  3. #include <cstdlib>
  4. #include <utility>
  5. #include <mutex>
  6. // #include <atomic>
  7. /**
  8. * @brief 这里采用零公摊的方式,设置多大的空间,就有多大的空间可以使用
  9. * 1、如果队列是空,m_rear和m_front都设置为-1
  10. * 2、m_rear指向最新入队的元素的下一个位置
  11. * 3、m_front指向需要出队的第一个元素
  12. * 4、环形队列自带互斥锁
  13. *
  14. * 判断队列满:
  15. * m_rear == m_front,并且此时都不等于 -1
  16. *
  17. * 判断队列空:
  18. * m_rear == m_front,并且都等于 -1
  19. *
  20. * 获取队列大小:
  21. * 基本原则就是m_rear后面跟着的是有效值,m_front后面跟着的是已经出队的大小
  22. * m_rear > m_front,返回 m_rear - m_front
  23. * m_front > m_rear,返回 m_capacity - (m_front - m_rear)
  24. * m_rear == m_front,且不等于-1,返回 m_capacity
  25. * m_rear == m_front,且等于-1,返回 0
  26. *
  27. * @tparam T 模版类型
  28. */
  29. template<typename T>
  30. class RingQueue
  31. {
  32. public:
  33. RingQueue();
  34. RingQueue(long size);
  35. ~RingQueue();
  36. /* 设置队列大小 */
  37. void setQueueSize(long size);
  38. /* 入队 */
  39. bool enQueue(const T& data);
  40. bool enQueue(T&& data);
  41. /* 出队 */
  42. bool deQueue(T& data);
  43. T& deQueue();
  44. /* 获取队列中第一个值(下一个出队的元素),但是不出队 */
  45. T& front();
  46. /* 获取队列中将要入队的位置的元素(如果队列中存储的是指针,这里就是获取这块地址的指针) */
  47. T& back();
  48. /* 获取队列大小,队列中有效值的大小 */
  49. long getQueueSize();
  50. /* 获取队列容量 */
  51. long getQueueCapacity();
  52. /* 判断队列是否为空 */
  53. bool isEmpty();
  54. /* 判断队列是否已满 */
  55. bool isFull();
  56. private:
  57. std::mutex m_mutex; /* 互斥锁 */
  58. T* m_queue = nullptr; /* 队列 */
  59. long m_capacity = 0; /* 队列容量 */
  60. long m_front = 0; /* 队头 */
  61. long m_rear = 0; /* 队尾 */
  62. };
  63. /* =====================================================================
  64. * ***************************** 函数实现 *****************************
  65. * ===================================================================== */
  66. /* 这个构造函数需要调用 setQueueSize 设置环形队列的大小 */
  67. template<typename T>
  68. RingQueue<T>::RingQueue() : m_capacity(0) , m_front(-1), m_rear(-1)
  69. {
  70. }
  71. template<typename T>
  72. RingQueue<T>::RingQueue(long capacicy) : m_capacity(capacicy)
  73. {
  74. m_front = -1;
  75. m_rear = -1;
  76. m_queue = new T[m_capacity];
  77. }
  78. template<typename T>
  79. RingQueue<T>::~RingQueue()
  80. {
  81. if(m_queue != nullptr)
  82. {
  83. delete[] m_queue;
  84. m_queue = nullptr;
  85. }
  86. }
  87. /**
  88. * @brief 设置队列大小
  89. * 注意:使用这个设置,如果队列中存储的是指针,指针的内存区域需要在调用这个函数之前释放,不然可能会造成
  90. * 内存泄漏
  91. *
  92. * @tparam T
  93. * @param size
  94. */
  95. template<typename T>
  96. void RingQueue<T>::setQueueSize(long size)
  97. {
  98. if(m_queue != nullptr)
  99. {
  100. delete[] m_queue;
  101. m_queue = nullptr;
  102. }
  103. m_capacity = size;
  104. m_front = -1;
  105. m_rear = -1;
  106. m_queue = new T[m_capacity];
  107. }
  108. /* 入队 */
  109. template<typename T>
  110. bool RingQueue<T>::enQueue(const T& data)
  111. {
  112. m_mutex.lock();
  113. /* 先检查队列是否还有剩余空间 */
  114. if(isFull())
  115. {
  116. return false;
  117. }
  118. else if(m_rear == -1)
  119. {
  120. m_front = 0;
  121. m_rear = 0;
  122. }
  123. /* 数据入队 */
  124. m_queue[m_rear] = data;
  125. m_rear = (m_rear + 1) % m_capacity;
  126. m_mutex.unlock();
  127. return true;
  128. }
  129. /* 入队,传入右值 */
  130. template<typename T>
  131. bool RingQueue<T>::enQueue(T&& data)
  132. {
  133. m_mutex.lock();
  134. /* 先检查队列是否还有剩余空间 */
  135. if(isFull())
  136. {
  137. return false;
  138. }
  139. else if(m_rear == -1)
  140. {
  141. m_front = 0;
  142. m_rear = 0;
  143. }
  144. m_queue[m_rear] = std::move(data);
  145. m_rear = (m_rear + 1) % m_capacity;
  146. m_mutex.unlock();
  147. return true;
  148. }
  149. /* 出队 */
  150. template<typename T>
  151. bool RingQueue<T>::deQueue(T& data)
  152. {
  153. m_mutex.lock();
  154. if(isEmpty())
  155. {
  156. return false;
  157. }
  158. data = std::move(m_queue[m_front]);
  159. /* 判断队列是否为空了 */
  160. m_front = (m_front + 1) % m_capacity;
  161. if(m_front == m_rear)
  162. {
  163. m_front = -1;
  164. m_rear = -1;
  165. }
  166. m_mutex.unlock();
  167. return true;
  168. }
  169. /* 出队 */
  170. template<typename T>
  171. T& RingQueue<T>::deQueue()
  172. {
  173. std::lock_guard<std::mutex> lock(m_mutex);
  174. if(isEmpty())
  175. {
  176. return T();
  177. }
  178. long tmp = m_front;
  179. m_front = (m_front + 1) % m_capacity;
  180. if(m_front == m_rear)
  181. {
  182. m_front = -1;
  183. m_rear = -1;
  184. }
  185. return std::move(m_queue[tmp]);
  186. }
  187. /* 获取队列中第一个值(下一个出队的元素),但是不出队 */
  188. template<typename T>
  189. T& RingQueue<T>::front()
  190. {
  191. std::lock_guard<std::mutex> lock(m_mutex);
  192. if(isEmpty())
  193. {
  194. return T();
  195. }
  196. return m_queue[m_front];
  197. }
  198. /* 获取队列中将要入队的位置的元素(如果队列中存储的是指针,这里就是获取这块地址的指针) */
  199. template<typename T>
  200. T& RingQueue<T>::back()
  201. {
  202. std::lock_guard<std::mutex> lock(m_mutex);
  203. if(isEmpty())
  204. {
  205. return T();
  206. }
  207. return m_queue[m_rear];
  208. }
  209. /* 获取队列中有效值的大小 */
  210. template<typename T>
  211. long RingQueue<T>::getQueueSize()
  212. {
  213. if(m_rear == -1)
  214. {
  215. return 0;
  216. }
  217. else if(m_rear > m_front)
  218. {
  219. return m_rear - m_front;
  220. }
  221. else if(m_rear < m_front)
  222. {
  223. return m_capacity - ( m_front - m_rear );
  224. }
  225. /* 这时候是队列满 */
  226. return m_capacity;
  227. }
  228. /* 获取队列容量 */
  229. template<typename T>
  230. long RingQueue<T>::getQueueCapacity()
  231. {
  232. return m_capacity;
  233. }
  234. /**
  235. * @brief 判断队列是否为空
  236. *
  237. * @tparam T
  238. * @return true
  239. * @return false
  240. */
  241. template<typename T>
  242. bool RingQueue<T>::isEmpty()
  243. {
  244. if((m_front == m_rear) && (m_front == -1))
  245. {
  246. return true;
  247. }
  248. return false;
  249. }
  250. /**
  251. * @brief 判断队列是否已满,这里判断依赖入队和出队后的队头和队尾指针的位置
  252. * 1、队头和队尾指针相等,但是队尾指针不等于-1,表示队列已满
  253. *
  254. * @tparam T
  255. * @return true
  256. * @return false
  257. */
  258. template<typename T>
  259. bool RingQueue<T>::isFull()
  260. {
  261. /* 如果m_rear或者m_front不等于-1,说明此时里面有内容
  262. * 同时m_front == m_rear,队列就满了 */
  263. if(m_front == m_rear && m_rear != -1)
  264. {
  265. return true;
  266. }
  267. return false;
  268. }
  269. #endif /* RINGQUEUE_H */