forked from max0x7ba/atomic_queue
-
Notifications
You must be signed in to change notification settings - Fork 0
/
atomic_queue_mutex.h
79 lines (58 loc) · 2.88 KB
/
atomic_queue_mutex.h
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
/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
#ifndef ATOMIC_QUEUE_ATOMIC_QUEUE_SPIN_LOCK_H_INCLUDED
#define ATOMIC_QUEUE_ATOMIC_QUEUE_SPIN_LOCK_H_INCLUDED
// Copyright (c) 2019 Maxim Egorushkin. MIT License. See the full licence in file LICENSE.
#include "atomic_queue.h"
#include "spinlock.h"
#include <cassert>
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace atomic_queue {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template<class T, class Mutex, unsigned SIZE, bool MINIMIZE_CONTENTION>
class AtomicQueueMutexT {
static constexpr unsigned size_ = MINIMIZE_CONTENTION ? details::round_up_to_power_of_2(SIZE) : SIZE;
Mutex mutex_;
alignas(CACHE_LINE_SIZE) unsigned head_ = 0;
alignas(CACHE_LINE_SIZE) unsigned tail_ = 0;
alignas(CACHE_LINE_SIZE) T q_[size_] = {};
static constexpr int SHUFFLE_BITS =
details::GetIndexShuffleBits<MINIMIZE_CONTENTION, size_, CACHE_LINE_SIZE / sizeof(T)>::value;
using ScopedLock = typename Mutex::scoped_lock;
public:
using value_type = T;
template<class U>
bool try_push(U&& element) noexcept {
ScopedLock lock(this->mutex_);
if(this->head_ - this->tail_ < size_) {
q_[details::remap_index<SHUFFLE_BITS>(this->head_ % size_)] = std::forward<U>(element);
++this->head_;
return true;
}
return false;
}
bool try_pop(T& element) noexcept {
ScopedLock lock(this->mutex_);
if(this->head_ != this->tail_) {
element = std::move(q_[details::remap_index<SHUFFLE_BITS>(this->tail_ % size_)]);
++this->tail_;
return true;
}
return false;
}
bool was_empty() const noexcept {
return static_cast<int>(this->head_ - this->tail_) <= 0;
}
bool was_full() const noexcept {
return static_cast<int>(this->head_ - this->tail_) >= static_cast<int>(size_);
}
};
template<class T, unsigned SIZE, class Mutex, bool MINIMIZE_CONTENTION = true>
using AtomicQueueMutex = AtomicQueueMutexT<T, Mutex, SIZE, MINIMIZE_CONTENTION>;
template<class T, unsigned SIZE, bool MINIMIZE_CONTENTION = true>
using AtomicQueueSpinlock = AtomicQueueMutexT<T, Spinlock, SIZE, MINIMIZE_CONTENTION>;
template<class T, unsigned SIZE, bool MINIMIZE_CONTENTION = true>
using AtomicQueueSpinlockHle = AtomicQueueMutexT<T, SpinlockHle, SIZE, MINIMIZE_CONTENTION>;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
} // namespace atomic_queue
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#endif // ATOMIC_QUEUE_ATOMIC_QUEUE_SPIN_LOCK_H_INCLUDED