jaffarCommon
Loading...
Searching...
No Matches
concurrent.hpp
Go to the documentation of this file.
1#pragma once
2
8#include <atomic>
9#include <atomic_queue/include/atomic_queue/atomic_queue.h>
10#include <cstdint>
11#include <cstdlib>
12#include <cstring>
13#include <deque>
14#include <mutex>
15#include <oneapi/tbb/concurrent_map.h>
16#include <phmap/parallel_hashmap/phmap.h>
17#include <stddef.h>
18
19namespace jaffarCommon
20{
21
22namespace concurrent
23{
24
45template <class T>
47{
48public:
49 DrainBuffer() = default;
51 {
52 if (_buffer != nullptr) free(_buffer);
53 }
54
59 __JAFFAR_COMMON_INLINE__ void reserve(const size_t capacity)
60 {
61 _capacity = capacity;
62 _buffer = (T*)malloc(capacity * sizeof(T));
63 }
64
69 __JAFFAR_COMMON_INLINE__ void clear()
70 {
71 _count = 0;
72 _claim.store(0, std::memory_order_relaxed);
73 }
74
83 __JAFFAR_COMMON_INLINE__ void push_back_no_lock(T element) { _buffer[_count++] = element; }
84
93 __JAFFAR_COMMON_INLINE__ size_t pop_front_get_batch(T* elements, const size_t maxCount)
94 {
95 uint64_t observed = _claim.load(std::memory_order_acquire);
96 uint64_t desired;
97 uint32_t front;
98 size_t take;
99 do {
100 front = (uint32_t)(observed & 0xFFFFFFFFULL);
101 const uint32_t back = (uint32_t)(observed >> 32);
102 if ((size_t)front + (size_t)back >= _count) return 0; // empty
103 const size_t available = _count - (size_t)front - (size_t)back;
104 take = maxCount < available ? maxCount : available;
105 desired = (observed & 0xFFFFFFFF00000000ULL) | (uint64_t)(front + (uint32_t)take);
106 } while (_claim.compare_exchange_weak(observed, desired, std::memory_order_acq_rel, std::memory_order_acquire) == false);
107
108 memcpy(elements, &_buffer[front], take * sizeof(T));
109 return take;
110 }
111
117 __JAFFAR_COMMON_INLINE__ bool pop_front_get(T& element) { return pop_front_get_batch(&element, 1) == 1; }
118
124 __JAFFAR_COMMON_INLINE__ bool pop_back_get(T& element)
125 {
126 uint64_t observed = _claim.load(std::memory_order_acquire);
127 uint64_t desired;
128 uint32_t back;
129 do {
130 const uint32_t front = (uint32_t)(observed & 0xFFFFFFFFULL);
131 back = (uint32_t)(observed >> 32);
132 if ((size_t)front + (size_t)back >= _count) return false; // empty
133 desired = (observed & 0x00000000FFFFFFFFULL) | ((uint64_t)(back + 1) << 32);
134 } while (_claim.compare_exchange_weak(observed, desired, std::memory_order_acq_rel, std::memory_order_acquire) == false);
135
136 element = _buffer[_count - 1 - (size_t)back];
137 return true;
138 }
139
145 __JAFFAR_COMMON_INLINE__ size_t wasSize() const
146 {
147 const uint64_t observed = _claim.load(std::memory_order_relaxed);
148 const size_t claimed = (size_t)(observed & 0xFFFFFFFFULL) + (size_t)(observed >> 32);
149 return claimed >= _count ? 0 : _count - claimed;
150 }
151
152private:
156 T* _buffer = nullptr;
157
161 size_t _capacity = 0;
162
166 size_t _count = 0;
167
172 std::atomic<uint64_t> _claim{0};
173};
174
178template <class T>
179using atomicQueue_t = atomic_queue::AtomicQueueB<T>;
180
184template <class V>
185using HashSet_t = phmap::parallel_flat_hash_set<V, phmap::priv::hash_default_hash<V>, phmap::priv::hash_default_eq<V>, std::allocator<V>, 8, std::mutex>;
186
190template <class K, class V>
191using HashMap_t = phmap::parallel_flat_hash_map<K, V, phmap::priv::hash_default_hash<K>, phmap::priv::hash_default_eq<K>, std::allocator<std::pair<const K, V>>, 8, std::mutex>;
192
196template <class K, class V, class C = std::greater<K>>
197using concurrentMultimap_t = oneapi::tbb::concurrent_multimap<K, V, C>;
198
204template <class T>
205class Deque
206{
207public:
208 Deque() = default;
209 ~Deque() = default;
210
215 __JAFFAR_COMMON_INLINE__ auto& getInternalStorage() { return _internalDeque; }
216
224 __JAFFAR_COMMON_INLINE__ void push_back_no_lock(T element)
225 {
226 _internalDeque.push_back(element);
227 _size.fetch_add(1, std::memory_order_relaxed);
228 }
229
237 __JAFFAR_COMMON_INLINE__ void push_back(T element)
238 {
239 _mutex.lock();
240 _internalDeque.push_back(element);
241 _size.fetch_add(1, std::memory_order_relaxed);
242 _mutex.unlock();
243 }
244
252 __JAFFAR_COMMON_INLINE__ void push_front_no_lock(T element)
253 {
254 _internalDeque.push_front(element);
255 _size.fetch_add(1, std::memory_order_relaxed);
256 }
257
265 __JAFFAR_COMMON_INLINE__ void push_front(T element)
266 {
267 _mutex.lock();
268 _internalDeque.push_front(element);
269 _size.fetch_add(1, std::memory_order_relaxed);
270 _mutex.unlock();
271 }
272
281 __JAFFAR_COMMON_INLINE__ T front() const { return _internalDeque.front(); }
282
291 __JAFFAR_COMMON_INLINE__ T back() const { return _internalDeque.back(); }
292
299 __JAFFAR_COMMON_INLINE__ void pop_front()
300 {
301 _mutex.lock();
302 _internalDeque.pop_front();
303 _size.fetch_sub(1, std::memory_order_relaxed);
304 _mutex.unlock();
305 }
306
313 __JAFFAR_COMMON_INLINE__ void pop_back()
314 {
315 _mutex.lock();
316 _internalDeque.pop_back();
317 _size.fetch_sub(1, std::memory_order_relaxed);
318 _mutex.unlock();
319 }
320
328 __JAFFAR_COMMON_INLINE__ bool pop_back_get(T& element)
329 {
330 _mutex.lock();
331
332 if (_internalDeque.empty())
333 {
334 _mutex.unlock();
335 return false;
336 }
337
338 element = _internalDeque.back();
339 _internalDeque.pop_back();
340 _size.fetch_sub(1, std::memory_order_relaxed);
341
342 _mutex.unlock();
343 return true;
344 }
345
353 __JAFFAR_COMMON_INLINE__ bool pop_front_get(T& element)
354 {
355 _mutex.lock();
356
357 if (_internalDeque.empty())
358 {
359 _mutex.unlock();
360 return false;
361 }
362
363 element = _internalDeque.front();
364 _internalDeque.pop_front();
365 _size.fetch_sub(1, std::memory_order_relaxed);
366
367 _mutex.unlock();
368 return true;
369 }
370
386 __JAFFAR_COMMON_INLINE__ size_t pop_front_get_batch(T* elements, const size_t maxCount)
387 {
388 _mutex.lock();
389
390 size_t count = 0;
391 while (count < maxCount && _internalDeque.empty() == false)
392 {
393 elements[count++] = _internalDeque.front();
394 _internalDeque.pop_front();
395 }
396 if (count > 0) _size.fetch_sub(count, std::memory_order_relaxed);
397
398 _mutex.unlock();
399 return count;
400 }
401
410 __JAFFAR_COMMON_INLINE__ size_t wasSize() const { return _size.load(std::memory_order_relaxed); }
411
412private:
416 std::mutex _mutex;
417
422 std::atomic<size_t> _size{0};
423
427 std::deque<T> _internalDeque;
428};
429
430} // namespace concurrent
431
432} // namespace jaffarCommon
Definition concurrent.hpp:206
__JAFFAR_COMMON_INLINE__ bool pop_front_get(T &element)
Definition concurrent.hpp:353
__JAFFAR_COMMON_INLINE__ void pop_front()
Definition concurrent.hpp:299
__JAFFAR_COMMON_INLINE__ void push_back(T element)
Definition concurrent.hpp:237
__JAFFAR_COMMON_INLINE__ size_t pop_front_get_batch(T *elements, const size_t maxCount)
Definition concurrent.hpp:386
__JAFFAR_COMMON_INLINE__ auto & getInternalStorage()
Definition concurrent.hpp:215
__JAFFAR_COMMON_INLINE__ void push_front(T element)
Definition concurrent.hpp:265
__JAFFAR_COMMON_INLINE__ bool pop_back_get(T &element)
Definition concurrent.hpp:328
__JAFFAR_COMMON_INLINE__ size_t wasSize() const
Definition concurrent.hpp:410
__JAFFAR_COMMON_INLINE__ void push_front_no_lock(T element)
Definition concurrent.hpp:252
__JAFFAR_COMMON_INLINE__ T front() const
Definition concurrent.hpp:281
__JAFFAR_COMMON_INLINE__ void push_back_no_lock(T element)
Definition concurrent.hpp:224
__JAFFAR_COMMON_INLINE__ void pop_back()
Definition concurrent.hpp:313
__JAFFAR_COMMON_INLINE__ T back() const
Definition concurrent.hpp:291
Definition concurrent.hpp:47
__JAFFAR_COMMON_INLINE__ size_t pop_front_get_batch(T *elements, const size_t maxCount)
Definition concurrent.hpp:93
__JAFFAR_COMMON_INLINE__ void clear()
Definition concurrent.hpp:69
__JAFFAR_COMMON_INLINE__ bool pop_front_get(T &element)
Definition concurrent.hpp:117
__JAFFAR_COMMON_INLINE__ void push_back_no_lock(T element)
Definition concurrent.hpp:83
__JAFFAR_COMMON_INLINE__ size_t wasSize() const
Definition concurrent.hpp:145
__JAFFAR_COMMON_INLINE__ bool pop_back_get(T &element)
Definition concurrent.hpp:124
__JAFFAR_COMMON_INLINE__ void reserve(const size_t capacity)
Definition concurrent.hpp:59
atomic_queue::AtomicQueueB< T > atomicQueue_t
Definition concurrent.hpp:179
oneapi::tbb::concurrent_multimap< K, V, C > concurrentMultimap_t
Definition concurrent.hpp:197
phmap::parallel_flat_hash_set< V, phmap::priv::hash_default_hash< V >, phmap::priv::hash_default_eq< V >, std::allocator< V >, 8, std::mutex > HashSet_t
Definition concurrent.hpp:185
phmap::parallel_flat_hash_map< K, V, phmap::priv::hash_default_hash< K >, phmap::priv::hash_default_eq< K >, std::allocator< std::pair< const K, V > >, 8, std::mutex > HashMap_t
Definition concurrent.hpp:191