forked from ChunelFeng/CGraph
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathUAtomicRingBufferQueue.h
More file actions
214 lines (189 loc) · 6.21 KB
/
UAtomicRingBufferQueue.h
File metadata and controls
214 lines (189 loc) · 6.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/***************************
@Author: Chunel
@Contact: chunel@foxmail.com
@File: UAtomicRingBufferQueue.h
@Time: 2022/10/22 22:32
@Desc: 本 queue 仅支持单入单出模式
***************************/
#ifndef CGRAPH_UATOMICRINGBUFFERQUEUE_H
#define CGRAPH_UATOMICRINGBUFFERQUEUE_H
#include <vector>
#include <atomic>
#include <chrono>
#include "UQueueObject.h"
CGRAPH_NAMESPACE_BEGIN
template<typename T, CUint capacity = CGRAPH_DEFAULT_RINGBUFFER_SIZE>
class UAtomicRingBufferQueue : public UQueueObject {
public:
explicit UAtomicRingBufferQueue() {
head_ = 0;
tail_ = 0;
capacity_ = capacity;
ring_buffer_queue_.resize(capacity_);
}
~UAtomicRingBufferQueue() override {
clear();
}
/**
* 设置容量信息
* @param size
* @return
* @notice 谨慎使用,push信息之后,不推荐使用
*/
UAtomicRingBufferQueue* setCapacity(CUint size) {
capacity_ = size;
ring_buffer_queue_.resize(capacity_);
return this;
}
/**
* 获取容量信息
* @return
*/
CUint getCapacity() const {
return capacity_;
}
/**
* 写入信息
* @tparam TImpl
* @param value
* @param strategy
* @return
*/
template<class TImpl = T>
CVoid push(const TImpl& value, URingBufferPushStrategy strategy) {
{
CGRAPH_UNIQUE_LOCK lk(mutex_);
if (isFull()) {
switch (strategy) {
case URingBufferPushStrategy::WAIT:
push_cv_.wait(lk, [this] { return !isFull(); });
break;
case URingBufferPushStrategy::REPLACE:
head_ = (head_ + 1) % capacity_;
break;
case URingBufferPushStrategy::DROP:
return; // 直接返回,不写入即可
}
}
ring_buffer_queue_[tail_] = std::move(c_make_unique<TImpl>(value));
tail_ = (tail_ + 1) % capacity_;
}
pop_cv_.notify_one();
}
/**
* 写入智能指针类型的信息
* @tparam TImpl
* @param value
* @param strategy
* @return
*/
template<class TImpl = T>
CVoid push(std::unique_ptr<TImpl>& value, URingBufferPushStrategy strategy) {
{
CGRAPH_UNIQUE_LOCK lk(mutex_);
if (isFull()) {
switch (strategy) {
case URingBufferPushStrategy::WAIT:
push_cv_.wait(lk, [this] { return !isFull(); });
break;
case URingBufferPushStrategy::REPLACE:
head_ = (head_ + 1) % capacity_;
break;
case URingBufferPushStrategy::DROP:
return; // 直接返回,不写入即可
}
}
ring_buffer_queue_[tail_] = std::move(value);
tail_ = (tail_ + 1) % capacity_;
}
pop_cv_.notify_one();
}
/**
* 等待弹出信息
* @param value
* @param timeout
* @return
*/
template<class TImpl = T>
CStatus waitPopWithTimeout(TImpl& value, CMSec timeout) {
CGRAPH_FUNCTION_BEGIN
{
CGRAPH_UNIQUE_LOCK lk(mutex_);
if (isEmpty()
&& !pop_cv_.wait_for(lk, std::chrono::milliseconds(timeout),
[this] { return !isEmpty(); })) {
// 如果timeout的时间内,等不到消息,则返回错误信息
CGRAPH_RETURN_ERROR_STATUS("receive message timeout.")
}
value = *ring_buffer_queue_[head_]; // 这里直接进行值copy
head_ = (head_ + 1) % capacity_;
}
push_cv_.notify_one();
CGRAPH_FUNCTION_END
}
/**
* 等待弹出信息。ps:当入参为智能指针的情况
* @tparam TImpl
* @param value
* @param timeout
* @return
*/
template<class TImpl = T>
CStatus waitPopWithTimeout(std::unique_ptr<TImpl>& value, CMSec timeout) {
CGRAPH_FUNCTION_BEGIN
{
CGRAPH_UNIQUE_LOCK lk(mutex_);
if (isEmpty()
&& !pop_cv_.wait_for(lk, std::chrono::milliseconds(timeout),
[this] { return !isEmpty(); })) {
// 如果timeout的时间内,等不到消息,则返回错误信息
CGRAPH_RETURN_ERROR_STATUS("receive message timeout.")
}
/**
* 当传入的内容,是智能指针的时候,
* 这里就直接通过 move转移过去好了,跟直接传值的方式,保持区别
*/
value = std::move(ring_buffer_queue_[head_]);
head_ = (head_ + 1) % capacity_;
}
push_cv_.notify_one();
CGRAPH_FUNCTION_END
}
/**
* 清空所有的数据
* @return
*/
CStatus clear() {
CGRAPH_FUNCTION_BEGIN
ring_buffer_queue_.resize(0);
head_ = 0;
tail_ = 0;
CGRAPH_FUNCTION_END
}
protected:
/**
* 当前队列是否为满
* @return
*/
CBool isFull() {
// 空出来一个位置,这个时候不让 tail写入
return head_ == (tail_ + 1) % capacity_;
}
/**
* 当前队列是否为空
* @return
*/
CBool isEmpty() {
return head_ == tail_;
}
CGRAPH_NO_ALLOWED_COPY(UAtomicRingBufferQueue)
private:
CUint head_; // 头结点位置
CUint tail_; // 尾结点位置
CUint capacity_; // 环形缓冲的容量大小
std::condition_variable push_cv_; // 写入的条件变量。为了保持语义完整,也考虑今后多入多出的可能性,不使用 父类中的 cv_了
std::condition_variable pop_cv_; // 读取的条件变量
std::vector<std::unique_ptr<T> > ring_buffer_queue_; // 环形缓冲区
};
CGRAPH_NAMESPACE_END
#endif //CGRAPH_UATOMICRINGBUFFERQUEUE_H