1 #include "hmbdc/Copyright.hpp" 3 #include "hmbdc/Compile.hpp" 4 #include "hmbdc/time/Time.hpp" 5 #include "hmbdc/Config.hpp" 7 #include <condition_variable> 11 namespace hmbdc {
namespace pattern {
13 namespace blocking_buffer_detail {
19 using value_type =
void *;
21 : maxItemSize_(maxItemSize)
25 store_ = (
char*)memalign(SMP_CACHE_BYTES, capacity*maxItemSize);
35 value_type getItem(
size_t seq) {
36 return store_ + seq % capacity_ * maxItemSize_;
39 size_t maxItemSize()
const {
return maxItemSize_;}
40 size_t capacity()
const {
return capacity_;}
41 void put(
void const* item,
size_t sizeHint = 0) {
42 std::unique_lock<std::mutex> lck(mutex_);
43 hasSlot_.wait(lck, [
this]{
return capacity_ > size_;});
44 memcpy(getItem(seq_++), item, sizeHint?sizeHint:maxItemSize_);
47 hasItem_.notify_one();
51 template <
typename T,
typename... Ts>
53 put(T&& item, Ts&&... items) {
54 std::unique_lock<std::mutex> lck(mutex_);
55 hasSlot_.wait(lck, [
this]{
return capacity_ > size_ +
sizeof...(Ts);});
56 fill(std::forward<T>(item), std::forward<Ts>(items)...);
57 size_ +=
sizeof...(items) + 1;
58 if (size_ ==
sizeof...(items) + 1) {
60 hasItem_.notify_one();
64 template <
typename It>
66 tryPutBatch(It begin,
size_t n) {
67 std::unique_lock<std::mutex> lck(mutex_);
68 if (hasSlot_.wait_for(
69 lck, std::chrono::seconds(0), [
this, n]{return capacity_ > size_ + n - 1;})) {
74 hasItem_.notify_all();
81 template <
typename Item,
typename It>
83 tryPutBatchInPlace(It begin,
size_t n) {
84 std::unique_lock<std::mutex> lck(mutex_);
85 if (hasSlot_.wait_for(
86 lck, std::chrono::seconds(0), [
this, n]{return capacity_ > size_ + n - 1;})) {
87 fillBatchInPlace<Item>(begin, n);
91 hasItem_.notify_all();
99 template <
typename T>
void putSome(T
const& item) {put(&item);}
100 template <
typename T,
typename ...Args>
101 void putInPlace(Args&&... args) {
102 std::unique_lock<std::mutex> lck(mutex_);
103 hasSlot_.wait(lck, [
this](){
return capacity_ > size_;});
104 new (getItem(seq_++)) T(std::forward<Args>(args)...);
107 hasItem_.notify_one();
110 template <
typename T,
typename ...Args>
111 bool tryPutInPlace(Args&&... args) {
112 std::unique_lock<std::mutex> lck(mutex_);
113 if (!hasSlot_.wait_for(lck, std::chrono::seconds(0), [
this](){return capacity_ > size_;}))
115 new (getItem(seq_++)) T(std::forward<Args>(args)...);
118 hasItem_.notify_one();
123 bool tryPut(
void const* item,
size_t sizeHint = 0
125 std::unique_lock<std::mutex> lck(mutex_);
126 if (!hasSlot_.wait_for(lck, std::chrono::nanoseconds(timeout.nanoseconds())
127 , [
this](){
return capacity_ > size_;}))
129 memcpy(getItem(seq_++), item, sizeHint?sizeHint:maxItemSize_);
132 hasItem_.notify_one();
137 template <
typename T>
138 bool tryPut(T
const& item
140 return tryPut(&item,
sizeof(item), timeout);
143 bool isFull()
const {
return size_ == capacity_;}
144 void take(
void *dest,
size_t sizeHint = 0) {
145 std::unique_lock<std::mutex> lck(mutex_);
146 hasItem_.wait(lck, [
this](){
return size_;});
147 memcpy(dest, getItem(seq_ - size_), sizeHint?sizeHint:maxItemSize_);
148 if (size_-- == capacity_) {
150 hasSlot_.notify_all();
154 template <
typename T>
156 take(&dest,
sizeof(T));
160 bool tryTake(
void *dest,
size_t sizeHint = 0,
time::Duration timeout = time::Duration::seconds(0)) {
161 std::unique_lock<std::mutex> lck(mutex_);
162 if (!hasItem_.wait_for(lck, std::chrono::nanoseconds(timeout.nanoseconds()), [
this](){
return size_;}))
return false;
163 memcpy(dest, getItem(seq_ - size_), sizeHint?sizeHint:maxItemSize_);
164 if (size_-- == capacity_) {
166 hasSlot_.notify_all();
171 template <
typename T>
172 bool tryTake(T& dest) {
173 return tryTake(&dest,
sizeof(T));
176 template <
typename itOut>
177 size_t take(itOut b, itOut e) {
178 std::unique_lock<std::mutex> lck(mutex_);
179 hasItem_.wait(lck, [
this](){
return size_;});
181 while (s && b != e) {
182 memcpy(&*b++, getItem(seq_ - s--), std::min(maxItemSize_,
sizeof(*b)));
184 auto ret = size_ - s;
186 if (size_ + ret == capacity_) {
188 hasSlot_.notify_all();
195 void wasteAfterPeek(
size_t len) {
196 std::unique_lock<std::mutex> lck(mutex_);
197 if (size_ == capacity_) hasSlot_.notify_all();
202 std::unique_lock<std::mutex> lck(mutex_);
203 hasItem_.wait_for(lck, std::chrono::nanoseconds(timeout.nanoseconds())
204 , [
this](){
return size_;});
207 size_t remainingSize()
const {
213 hasSlot_.notify_all();
218 template <
typename T,
typename... Ts>
220 fill(T&& item, Ts&&... items) {
221 new (getItem(seq_++)) T(std::forward<T>(item));
222 fill(std::forward<Ts>(items)...);
225 template <
typename It>
227 fillBatch(It begin,
size_t n) {
228 for (
auto it = begin; n; ++it, --n) {
229 using T = decltype(*begin);
230 new (getItem(seq_++)) T(*it);
234 template <
typename Item,
typename It>
236 fillBatchInPlace(It begin,
size_t n) {
237 for (
auto it = begin; n; ++it, --n) {
238 new (getItem(seq_++)) Item(*it);
248 std::condition_variable hasItem_;
249 std::condition_variable hasSlot_;
252 namespace blocking_buffer_detail {
254 using Sequence = uint64_t;
256 : buf_(buf), seq_(seq){}
257 iterator() : buf_(
nullptr), seq_(0){}
258 void clear() {buf_ =
nullptr;}
260 iterator& operator ++() HMBDC_RESTRICT {
265 iterator operator ++(
int) HMBDC_RESTRICT {
271 iterator operator + (
size_t dis)
const HMBDC_RESTRICT {
277 iterator& operator += (
size_t dis) HMBDC_RESTRICT {
282 size_t operator - (
iterator const& other)
const HMBDC_RESTRICT {
283 return seq_ - other.seq_;
286 explicit operator bool()
const HMBDC_RESTRICT {
290 bool operator < (
iterator const& other)
const HMBDC_RESTRICT {
291 return seq_ < other.seq_;
294 bool operator == (
iterator const& other)
const HMBDC_RESTRICT {
return seq_ == other.seq_;}
295 bool operator != (
iterator const& other)
const HMBDC_RESTRICT {
return seq_ != other.seq_;}
296 void* operator*()
const HMBDC_RESTRICT {
return buf_->getItem(seq_);}
297 template <
typename T> T&
get()
const HMBDC_RESTRICT {
return *
static_cast<T*
>(**this);}
298 template <
typename T>
299 T* operator->() HMBDC_RESTRICT {
return static_cast<T*
>(buf_->getItem(seq_));}
310 std::unique_lock<std::mutex> lck(mutex_);
317 BlockingBuffer::iterator
320 std::unique_lock<std::mutex> lck(mutex_);
322 return iterator(
this, seq_ - size_);
Definition: BlockingBuffer.hpp:17
Definition: BlockingBuffer.hpp:253
Definition: LockFreeBufferMisc.hpp:89