RingQueueManualMutex.hpp 12 KB

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