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 80 81 82 83 84 85 86 87 88 89
|
/*
==============================================================================
LockFreeQueue.h
Created: 1 Apr 2014 6:27:32pm
Author: Tom Maisey
==============================================================================
*/
#pragma once
/**
* A simple single producer & consumer lock free queue, based on Herb Sutter's code:
* http://www.drdobbs.com/parallel/writing-lock-free-code-a-corrected-queue/
*
* This is a linked list, which can expand arbitrarily without losing old data,
* but which has poor cache locality (I plan to write a ring buffer version soon).
*/
template <typename T>
class LockFreeQueue
{
public:
LockFreeQueue()
{
first = new Node(T()); // Dummy seperator.
last.set(first);
divider.set(first);
}
~LockFreeQueue()
{
while (first != nullptr)
{
Node* toDel = first;
first = toDel->next;
delete toDel;
}
}
/**
* Add an item to the queue. Obviously, should only be called from producer's thread.
*/
void produce(const T& t)
{
last.get()->next = new Node(t);
last.set(last.get()->next);
while (first != divider.get())
{ // trim unused nodes
Node* tmp = first;
first = first->next;
delete tmp;
}
}
/**
* Consume an item in the queue. Returns false if no items left to consume.
*/
bool consume(T& result)
{
Node* div = divider.get();
if (div != last.get())
{ // if queue is nonempty
result = div->next->value; // copy requested value
divider.set(div->next); // publish that we took it
return true;
}
return false;
}
private:
struct Node
{
Node(const T& val)
: value(val)
{}
T value;
Node* next{ nullptr };
};
Node* first{ nullptr };
Atomic<Node*> divider, last;
};
|