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 90 91 92 93 94 95 96 97 98 99 100 101
| #ifndef LOCK_FREE_QUEUE_HPP
#define LOCK_FREE_QUEUE_HPP
#include <atomic>
// Note : implementation is from
// http://www.drdobbs.com/parallel/writing-lock-free-code-a-corrected-queue/210604448
template<typename T>
class lock_free_queue
{
struct node
{
node() : next(nullptr) {}
node(const T& t) : data(t), next(nullptr) {}
T data;
node* next;
};
node* first;
std::atomic<node*> dummy, last;
public :
lock_free_queue() {
// Always keep a dummy separator between head and tail
first = last = dummy = new node();
}
~lock_free_queue() {
// Clear the whole queue
while (first != nullptr)
{
node* temp = first;
first = temp->next;
delete temp;
}
}
// Disable copy
lock_free_queue(const lock_free_queue& q) = delete;
lock_free_queue& operator = (const lock_free_queue& q) = delete;
// To be called by the 'producer' thread
void push(const T& t) {
// Add the new item to the queue
(*last).next = new node(t);
last = (*last).next;
// Clear consumed items
while (first != dummy)
{
node* temp = first;
first = temp->next;
delete temp;
}
}
// To be called by the 'consumer' thread
bool pop(T& t) {
// Return false if queue is empty
if (dummy != last)
{
// Consume the value
t = (*dummy).next->data;
dummy = (*dummy).next;
return true;
}
else
return false;
}
// To be called by the 'consumer' thread
bool empty() const {
return dummy == last;
}
// This method should not be used in concurrent situations
void clear() {
while (first != dummy)
{
node* temp = first;
first = temp->next;
delete temp;
}
first = dummy.load();
while (first->next != nullptr)
{
node* temp = first;
first = temp->next;
delete temp;
}
last = dummy = first;
}
};
#endif |
Partager