RingQueue.hpp 13 KB

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