RingQueue.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. #ifndef RINGQUEUE_H
  2. #define RINGQUEUE_H
  3. #include <cstdlib>
  4. #include <utility>
  5. #include <mutex>
  6. #include <condition_variable>
  7. // #include <atomic>
  8. /**
  9. * @brief 这里采用零公摊的方式,设置多大的空间,就有多大的空间可以使用
  10. * 1、m_rear指向最新入队的元素的下一个位置,就是下个将要入队的元素位置
  11. * 2、m_front指向需要出队的第一个元素
  12. * 3、环形队列自带互斥锁
  13. *
  14. * 注意:
  15. * 使用时要注意,不带NoBlock的都是阻塞函数
  16. *
  17. * 判断队列满:
  18. * m_rear == m_front,并且此时都不等于 -1
  19. *
  20. * 判断队列空:
  21. * m_rear == m_front,并且都等于 -1
  22. *
  23. * 获取队列大小:
  24. * 基本原则就是m_rear后面跟着的是有效值,m_front后面跟着的是已经出队的大小
  25. * m_rear > m_front,返回 m_rear - m_front
  26. * m_front > m_rear,返回 m_capacity - (m_front - m_rear)
  27. * m_rear == m_front,且不等于-1,返回 m_capacity
  28. * m_rear == m_front,且等于-1,返回 0
  29. *
  30. * @tparam T 模版类型
  31. */
  32. template<typename T>
  33. class RingQueue
  34. {
  35. public:
  36. RingQueue();
  37. RingQueue(long size);
  38. ~RingQueue();
  39. /* 设置队列大小 */
  40. void setQueueSize(long size);
  41. long QueueSize() { return m_capacity; }
  42. /* 清空队列 */
  43. void clearQueue();
  44. /* 入队,默认是阻塞入队 */
  45. void push(const T& value);
  46. void push(T&& value);
  47. bool push_NoBlock(const T& value);
  48. bool push_NoBlock(T&& value);
  49. /* 出队,删除队列的首个元素
  50. * 注意,如果存储的是指针,需要手动释放该指针指向的内存区域,不然会造成内存泄漏 */
  51. void pop();
  52. /* 获取队列中第一个值),但是不出队
  53. * 阻塞的方式获取,如果队列为空,会一直阻塞住,直到获取到数据为止 */
  54. T front();
  55. /* 非阻塞的方式获取,队列为空返回false */
  56. bool front_NoBlock(T& t);
  57. /* 获取对立第一个数据,获取完立刻出队
  58. * 如果队列为空,会阻塞住,直到有数据为止 */
  59. T&& front_pop();
  60. // T&& front_pop_rvalue();
  61. bool front_pop_NoBlock(T& t);
  62. /* 获取队列大小,队列中有效值的大小 */
  63. long getQueueSize();
  64. /* 获取队列容量 */
  65. long getQueueCapacity();
  66. /* 判断队列是否为空 */
  67. bool isEmpty();
  68. /* 判断队列是否已满 */
  69. bool isFull();
  70. /* 退出所有可能的阻塞函数 */
  71. void exit();
  72. private:
  73. bool m_isExit = false; /* 是否退出,这个标识位是为了退出阻塞住的函数 */
  74. std::mutex m_mutex; /* 互斥锁 */
  75. T* m_queue = nullptr; /* 队列 */
  76. long m_capacity = 0; /* 队列容量 */
  77. long m_front = 0; /* 队头 */
  78. long m_rear = 0; /* 队尾 */
  79. std::condition_variable m_cond_NoFull; /* 非满条件变量 */
  80. std::condition_variable m_cond_NoEmpty; /* 非空条件变量 */
  81. };
  82. /* =====================================================================
  83. * ***************************** 函数实现 *****************************
  84. * ===================================================================== */
  85. /* 这个构造函数需要调用 setQueueSize 设置环形队列的大小 */
  86. template<typename T>
  87. RingQueue<T>::RingQueue() : m_capacity(0) , m_front(-1), m_rear(-1)
  88. {
  89. }
  90. template<typename T>
  91. RingQueue<T>::RingQueue(long capacicy) : m_capacity(capacicy)
  92. {
  93. m_front = -1;
  94. m_rear = -1;
  95. m_queue = new T[m_capacity];
  96. }
  97. template<typename T>
  98. RingQueue<T>::~RingQueue()
  99. {
  100. if(m_queue != nullptr)
  101. {
  102. delete[] m_queue;
  103. m_queue = nullptr;
  104. }
  105. }
  106. /**
  107. * @brief 设置队列大小
  108. * 注意:使用这个设置,如果队列中存储的是指针,指针的内存区域需要在调用这个函数之前释放,不然可能会造成
  109. * 内存泄漏
  110. *
  111. * @tparam T
  112. * @param size
  113. */
  114. template<typename T>
  115. void RingQueue<T>::setQueueSize(long size)
  116. {
  117. if(m_queue != nullptr)
  118. {
  119. delete[] m_queue;
  120. m_queue = nullptr;
  121. }
  122. m_capacity = size;
  123. m_front = -1;
  124. m_rear = -1;
  125. m_queue = new T[m_capacity];
  126. }
  127. /* 清空队列 */
  128. template<typename T>
  129. void RingQueue<T>::clearQueue()
  130. {
  131. m_mutex.lock();
  132. if(m_queue != nullptr)
  133. {
  134. delete[] m_queue;
  135. m_queue = nullptr;
  136. }
  137. m_front = -1;
  138. m_rear = -1;
  139. m_mutex.unlock();
  140. }
  141. /*************** 入队 *******************/
  142. template<typename T>
  143. void RingQueue<T>::push(const T& value)
  144. {
  145. {
  146. std::unique_lock<std::mutex> lock(m_mutex);
  147. m_cond_NoFull.wait(lock, [this](){
  148. return (!isFull() || m_isExit);
  149. });
  150. if(m_isExit)
  151. {
  152. return;
  153. }
  154. if(m_rear == -1)
  155. {
  156. m_front = 0;
  157. m_rear = 0;
  158. }
  159. m_queue[m_rear] = value;
  160. m_rear = (m_rear + 1) % m_capacity;
  161. }
  162. m_cond_NoEmpty.notify_all();
  163. }
  164. template<typename T>
  165. void RingQueue<T>::push(T&& value)
  166. {
  167. {
  168. std::unique_lock<std::mutex> lock(m_mutex);
  169. m_cond_NoFull.wait(lock, [this](){
  170. return (!isFull() || m_isExit);
  171. });
  172. if(m_isExit)
  173. {
  174. return;
  175. }
  176. if(m_rear == -1)
  177. {
  178. m_front = 0;
  179. m_rear = 0;
  180. }
  181. m_queue[m_rear] = std::move(value);
  182. m_rear = (m_rear + 1) % m_capacity;
  183. }
  184. m_cond_NoEmpty.notify_all();
  185. }
  186. /**
  187. * @brief 非阻塞的方式入队,如果队列已满,直接返回
  188. *
  189. */
  190. template<typename T>
  191. bool RingQueue<T>::push_NoBlock(const T& value)
  192. {
  193. {
  194. // std::unique_lock<std::mutex> lock(m_mutex, std::defer_lock);
  195. // if(!lock.try_lock())
  196. // {
  197. // return false;
  198. // }
  199. std::lock_guard<std::mutex> lock(m_mutex);
  200. /* 先检查队列是否还有剩余空间 */
  201. if(isFull())
  202. {
  203. return false;
  204. }
  205. else if(m_rear == -1)
  206. {
  207. m_front = 0;
  208. m_rear = 0;
  209. }
  210. m_queue[m_rear] = value;
  211. m_rear = (m_rear + 1) % m_capacity;
  212. }
  213. m_cond_NoEmpty.notify_all();
  214. return true;
  215. }
  216. template<typename T>
  217. bool RingQueue<T>::push_NoBlock(T&& value)
  218. {
  219. {
  220. // std::unique_lock<std::mutex> lock(m_mutex, std::defer_lock);
  221. // if(!lock.try_lock())
  222. // {
  223. // return false;
  224. // }
  225. std::lock_guard<std::mutex> lock(m_mutex);
  226. /* 先检查队列是否还有剩余空间 */
  227. if(isFull())
  228. {
  229. return false;
  230. }
  231. else if(m_rear == -1)
  232. {
  233. m_front = 0;
  234. m_rear = 0;
  235. }
  236. m_queue[m_rear] = std::move(value);
  237. m_rear = (m_rear + 1) % m_capacity;
  238. }
  239. m_cond_NoEmpty.notify_all();
  240. return true;
  241. }
  242. /**
  243. * @brief 出队,删除队列的首个元素
  244. * 注意,如果存储的是指针,需要手动释放该指针指向的内存区域,不然会造成内存泄漏
  245. *
  246. * @tparam T
  247. */
  248. template<typename T>
  249. void RingQueue<T>::pop()
  250. {
  251. {
  252. std::unique_lock<std::mutex> lock(m_mutex);
  253. if(isEmpty())
  254. {
  255. return;
  256. }
  257. m_front = (m_front + 1) % m_capacity;
  258. if(m_front == m_rear)
  259. {
  260. m_front = -1;
  261. m_rear = -1;
  262. }
  263. }
  264. m_cond_NoFull.notify_all();
  265. }
  266. /* 获取队列中第一个值,但是不出队
  267. * 阻塞的方式获取,如果队列为空,会一直阻塞住,直到获取到数据为止 */
  268. template<typename T>
  269. T RingQueue<T>::front()
  270. {
  271. T retValue;
  272. {
  273. std::unique_lock<std::mutex> lock(m_mutex);
  274. m_cond_NoEmpty.wait(lock, [this](){
  275. return (!isEmpty() || m_isExit);
  276. });
  277. if(m_isExit)
  278. {
  279. return retValue;
  280. }
  281. retValue = m_queue[m_front];
  282. }
  283. return retValue;
  284. }
  285. /* 获取队列中第一个值,但是不出队,非阻塞的方式获取 */
  286. template<typename T>
  287. bool RingQueue<T>::front_NoBlock(T& t)
  288. {
  289. {
  290. std::unique_lock<std::mutex> lock(m_mutex);
  291. if(isEmpty())
  292. {
  293. return false;
  294. }
  295. t = m_queue[m_front];
  296. }
  297. return true;
  298. }
  299. /* 获取对立第一个数据,获取完立刻出队
  300. * 如果队列为空,会阻塞住,直到有数据为止 */
  301. template<typename T>
  302. T&& RingQueue<T>::front_pop()
  303. {
  304. T ret;
  305. {
  306. std::unique_lock<std::mutex> lock(m_mutex);
  307. m_cond_NoEmpty.wait(lock, [this](){
  308. return (!isEmpty() || m_isExit);
  309. });
  310. if(m_isExit)
  311. {
  312. return std::move(ret);
  313. }
  314. ret = std::move(m_queue[m_front]);
  315. m_front = (m_front + 1) % m_capacity;
  316. if(m_front == m_rear)
  317. {
  318. m_front = -1;
  319. m_rear = -1;
  320. }
  321. }
  322. m_cond_NoFull.notify_all();
  323. return std::move(ret);
  324. }
  325. template<typename T>
  326. bool RingQueue<T>::front_pop_NoBlock(T& t)
  327. {
  328. {
  329. std::unique_lock<std::mutex> lock(m_mutex);
  330. if(isEmpty())
  331. {
  332. return false;
  333. }
  334. t = std::move(m_queue[m_front]);
  335. m_front = (m_front + 1) % m_capacity;
  336. if(m_front == m_rear)
  337. {
  338. m_front = -1;
  339. m_rear = -1;
  340. }
  341. }
  342. m_cond_NoFull.notify_all();
  343. return true;
  344. }
  345. /* 获取队列中有效值的大小 */
  346. template<typename T>
  347. long RingQueue<T>::getQueueSize()
  348. {
  349. std::lock_guard<std::mutex> lock(m_mutex);
  350. if(m_rear == -1)
  351. {
  352. return 0;
  353. }
  354. else if(m_rear > m_front)
  355. {
  356. return m_rear - m_front;
  357. }
  358. else if(m_rear < m_front)
  359. {
  360. return m_capacity - ( m_front - m_rear );
  361. }
  362. /* 这时候是队列满 */
  363. return m_capacity;
  364. }
  365. /* 获取队列容量 */
  366. template<typename T>
  367. long RingQueue<T>::getQueueCapacity()
  368. {
  369. std::lock_guard<std::mutex> lock(m_mutex);
  370. return m_capacity;
  371. }
  372. /**
  373. * @brief 判断队列是否为空
  374. *
  375. * @tparam T
  376. * @return true
  377. * @return false
  378. */
  379. template<typename T>
  380. bool RingQueue<T>::isEmpty()
  381. {
  382. if((m_front == m_rear) && (m_front == -1))
  383. {
  384. return true;
  385. }
  386. return false;
  387. }
  388. /**
  389. * @brief 判断队列是否已满,这里判断依赖入队和出队后的队头和队尾指针的位置
  390. * 1、队头和队尾指针相等,但是队尾指针不等于-1,表示队列已满
  391. *
  392. * @tparam T
  393. * @return true
  394. * @return false
  395. */
  396. template<typename T>
  397. bool RingQueue<T>::isFull()
  398. {
  399. /* 如果m_rear或者m_front不等于-1,说明此时里面有内容
  400. * 同时m_front == m_rear,队列就满了 */
  401. if(m_front == m_rear && m_rear != -1)
  402. {
  403. return true;
  404. }
  405. return false;
  406. }
  407. /* 退出所有可能的阻塞函数 */
  408. template<typename T>
  409. void RingQueue<T>::exit()
  410. {
  411. m_isExit = true;
  412. m_cond_NoFull.notify_all();
  413. m_cond_NoEmpty.notify_all();
  414. }
  415. #endif /* RINGQUEUE_H */