mirror of
https://codeberg.org/armin/justasample.git
synced 2026-09-01 12:20:48 +02:00
init
This commit is contained in:
commit
d21bc831e1
178 changed files with 24136 additions and 0 deletions
139
External/readerwriterqueue/benchmarks/ext/1024cores/spscqueue.h
vendored
Normal file
139
External/readerwriterqueue/benchmarks/ext/1024cores/spscqueue.h
vendored
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
#include "../../../atomicops.h"
|
||||
#include <cstdlib> // For std::size_t
|
||||
|
||||
// From http://www.1024cores.net/home/lock-free-algorithms/queues/unbounded-spsc-queue
|
||||
// (and http://software.intel.com/en-us/articles/single-producer-single-consumer-queue)
|
||||
|
||||
// load with 'consume' (data-dependent) memory ordering
|
||||
template<typename T>
|
||||
T load_consume(T const* addr)
|
||||
{
|
||||
// hardware fence is implicit on x86
|
||||
T v = *const_cast<T const volatile*>(addr);
|
||||
moodycamel::compiler_fence(moodycamel::memory_order_seq_cst);
|
||||
return v;
|
||||
}
|
||||
|
||||
// store with 'release' memory ordering
|
||||
template<typename T>
|
||||
void store_release(T* addr, T v)
|
||||
{
|
||||
// hardware fence is implicit on x86
|
||||
moodycamel::compiler_fence(moodycamel::memory_order_seq_cst);
|
||||
*const_cast<T volatile*>(addr) = v;
|
||||
}
|
||||
|
||||
// cache line size on modern x86 processors (in bytes)
|
||||
size_t const cache_line_size = 64;
|
||||
// single-producer/single-consumer queue
|
||||
template<typename T>
|
||||
class spsc_queue
|
||||
{
|
||||
public:
|
||||
spsc_queue()
|
||||
{
|
||||
node* n = new node;
|
||||
n->next_ = 0;
|
||||
tail_ = head_ = first_= tail_copy_ = n;
|
||||
}
|
||||
|
||||
explicit spsc_queue(size_t prealloc)
|
||||
{
|
||||
node* n = new node;
|
||||
n->next_ = 0;
|
||||
tail_ = head_ = first_ = tail_copy_ = n;
|
||||
|
||||
// [CD] Not (at all) the most efficient way to pre-allocate memory, but it works
|
||||
T dummy = T();
|
||||
for (size_t i = 0; i != prealloc; ++i) {
|
||||
enqueue(dummy);
|
||||
}
|
||||
for (size_t i = 0; i != prealloc; ++i) {
|
||||
try_dequeue(dummy);
|
||||
}
|
||||
}
|
||||
|
||||
~spsc_queue()
|
||||
{
|
||||
node* n = first_;
|
||||
do
|
||||
{
|
||||
node* next = n->next_;
|
||||
delete n;
|
||||
n = next;
|
||||
}
|
||||
while (n);
|
||||
}
|
||||
|
||||
void enqueue(T v)
|
||||
{
|
||||
node* n = alloc_node();
|
||||
n->next_ = 0;
|
||||
n->value_ = v;
|
||||
store_release(&head_->next_, n);
|
||||
head_ = n;
|
||||
}
|
||||
|
||||
// returns 'false' if queue is empty
|
||||
bool try_dequeue(T& v)
|
||||
{
|
||||
if (load_consume(&tail_->next_))
|
||||
{
|
||||
v = tail_->next_->value_;
|
||||
store_release(&tail_, tail_->next_);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// internal node structure
|
||||
struct node
|
||||
{
|
||||
node* next_;
|
||||
T value_;
|
||||
};
|
||||
|
||||
// consumer part
|
||||
// accessed mainly by consumer, infrequently be producer
|
||||
node* tail_; // tail of the queue
|
||||
|
||||
// delimiter between consumer part and producer part,
|
||||
// so that they situated on different cache lines
|
||||
char cache_line_pad_ [cache_line_size];
|
||||
|
||||
// producer part
|
||||
// accessed only by producer
|
||||
node* head_; // head of the queue
|
||||
node* first_; // last unused node (tail of node cache)
|
||||
node* tail_copy_; // helper (points somewhere between first_ and tail_)
|
||||
|
||||
node* alloc_node()
|
||||
{
|
||||
// first tries to allocate node from internal node cache,
|
||||
// if attempt fails, allocates node via ::operator new()
|
||||
|
||||
if (first_ != tail_copy_)
|
||||
{
|
||||
node* n = first_;
|
||||
first_ = first_->next_;
|
||||
return n;
|
||||
}
|
||||
tail_copy_ = load_consume(&tail_);
|
||||
if (first_ != tail_copy_)
|
||||
{
|
||||
node* n = first_;
|
||||
first_ = first_->next_;
|
||||
return n;
|
||||
}
|
||||
node* n = new node;
|
||||
return n;
|
||||
}
|
||||
|
||||
spsc_queue(spsc_queue const&);
|
||||
spsc_queue& operator = (spsc_queue const&);
|
||||
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue