Fwiw, check this out:
https://groups.google.com/d/topic/comp.lang.c++/yt27gw0cbyo/discussion
No padding and cache alignment here in the crude code, but the algorithm
is shown for spmc_queue::push and spmc_queue::flush ->
(trimmed from the original program) contained within the contents of the
link above: C++11 compatible...
__________________________
#define mb_relaxed std::memory_order_relaxed
#define mb_consume std::memory_order_consume
#define mb_acquire std::memory_order_acquire
#define mb_release std::memory_order_release
#define mb_acq_rel std::memory_order_acq_rel
#define mb_seq_cst std::memory_order_seq_cst
#define mb_fence(mb) std::atomic_thread_fence(mb)
// simple single producer/multi-consumer queue
struct node
{
node* m_next;
node() : m_next(nullptr) {} // tidy...
};
struct spmc_queue
{
std::atomic<node*> m_head;
spmc_queue() : m_head(nullptr) {}
// push a single node
void push(node* const n)
{
node* head = m_head.load(mb_relaxed);
for (;;)
{
n->m_next = head;
mb_fence(mb_release);
// failure updates head...
if (m_head.compare_exchange_weak(head, n, mb_relaxed))
{
break;
}
}
}
// try to flush all of our nodes
node* flush(node* const nhead = nullptr)
{
node* n = m_head.exchange(nhead, mb_relaxed);
if (n)
{
mb_fence(mb_acquire);
}
return n;
}
};
__________________________
Well, this is can be a queue and a stack at the same time... The
non-nullptr result from spmc_queue::flush can be used as-is for LIFO.
However, if you reverse the list, a FIFO nature pops out of the queue as
a whole. Any thoughts?