-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathLockFreeQueue.hpp
More file actions
155 lines (121 loc) · 3.93 KB
/
Copy pathLockFreeQueue.hpp
File metadata and controls
155 lines (121 loc) · 3.93 KB
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//--------------------------------------------------------------------
// LockFreeQueue.hpp.
// 09/10/2022. created.
// 09/03/2025. last modified.
//--------------------------------------------------------------------
// * LockFreeQueue - A Part of Agave(TM) Coroutine Framework
// (based on ISO C++20 or later).
// * if has any questions,
// * please contact me at 'full1900@outlook.com'.
// * by bubo.
//--------------------------------------------------------------------
#pragma once
#ifndef _LOCKFREE_QUEUE_HPP__
#define _LOCKFREE_QUEUE_HPP__
//--------------------------------------------------------------------
// headers.
//--------------------------------------------------------------------
#include <atomic>
#include <memory>
//--------------------------------------------------------------------
namespace agave
{
//--------------------------------------------------------------------
// lock free mechanism.
//--------------------------------------------------------------------
// Refer to the paper <Implementing Lock-Free Queues>
// by John D. Valois,
// Department of Computer Science Rensselaer Polytechnic Institute
// Troy, NY 12180.
// To appear in Proceedings of the Seventh International Conference on
// Parallel and Distributed Computing Systems,
// Las Vegas, NV, October 1994.
//--------------------------------------------------------------------
template <typename T>
class QueueNode
{
public:
T* data;
std::atomic<std::shared_ptr<QueueNode<T>>> next;
};
//--------------------------------------------------------------------
template <typename T>
class Queue
{
public:
//--------------------------------------------------------------------
Queue(void)
{
_head = std::shared_ptr<QueueNode<T>>{ new QueueNode<T>{ nullptr, nullptr } };
_tail.store(_head);
}
//--------------------------------------------------------------------
void push(T* data)
{
/* preparing for adding a new node. */
std::shared_ptr<QueueNode<T>> node{ new QueueNode<T>{ data, nullptr } };
std::shared_ptr<QueueNode<T>> tail, next;
while (true)
{
/* take the pointer of tail and
the pointer of next of tail. */
tail = _tail.load();
next = tail->next;
/* try loop again, if the pointer of tail is changed. */
if (_tail.load() != tail)
continue;
/* assist in advancing nodes of other threads. */
if (next)
{
_tail.compare_exchange_weak(tail, next);
continue;
}
/* break the loop, if inserts node successfully. */
if (tail->next.compare_exchange_weak(next, node))
break;
}
_tail.compare_exchange_weak(tail, node);
}
//--------------------------------------------------------------------
T* pop(void)
{
std::shared_ptr<QueueNode<T>> head, tail, next;
T* data{ nullptr };
while (true)
{
head = _head.load();
tail = _tail.load();
next = head->next;
/* try loop again, if the pointer of head is changed. */
if (_head.load() != head)
continue;
/* the queue is empty. */
if (head == tail && !next)
return nullptr;
if (head == tail && next)
{
/* assist in advancing nodes of other threads. */
_tail.compare_exchange_weak(tail, next);
continue;
}
if (_head.compare_exchange_weak(head, next))
{
data = next->data;
break;
}
}
return data;
}
//--------------------------------------------------------------------
bool is_empty(void) const
{
return _head.load() == _tail.load();
}
//--------------------------------------------------------------------
private:
std::atomic<std::shared_ptr<QueueNode<T>>> _head;
std::atomic<std::shared_ptr<QueueNode<T>>> _tail;
};
}
//--------------------------------------------------------------------
#endif // !_LOCKFREE_QUEUE_HPP__