-
Notifications
You must be signed in to change notification settings - Fork 0
/
lqueue.h
70 lines (61 loc) · 1.29 KB
/
lqueue.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
#ifndef __LQUEUE_H__
#define __LQUEUE_H__
/*
* Copyright (c) 2014 Pavel Shramov <[email protected]>
*
* lqueue is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <memory>
#include <atomic>
/*
* XXX: Probably there are some races...
*/
template <typename T>
class lqueue
{
struct node {
node * next;
T value;
node() : next(0), value() {}
};
std::atomic<node *> _head;
std::atomic<node *> _tail;
public:
lqueue() : _head(new node), _tail(_head.load()) {}
~lqueue()
{
for (auto ptr = _head.load(); ptr;)
{
std::unique_ptr<node> p(ptr);
ptr = ptr->next;
}
}
// Passing by value to have fast push(T &&)
void push(T value)
{
auto e = new node;
do {
auto p = _tail.load();
if (!_tail.compare_exchange_weak(p, e))
continue;
std::swap(p->value, value);
//XXX: Write barrier is needed here
std::atomic_thread_fence(std::memory_order_release);
p->next = e;
return;
} while (1);
}
std::pair<T, bool> pop()
{
do {
auto p = _head.load();
if (!p->next) return std::make_pair(T(), false);
if (!_head.compare_exchange_weak(p, p->next))
continue;
std::unique_ptr<node> ptr(p);
return std::make_pair(p->value, true);
} while (1);
}
};
#endif//__LQUEUE_H__