-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmcslock.cpp
More file actions
62 lines (53 loc) · 1.88 KB
/
Copy pathmcslock.cpp
File metadata and controls
62 lines (53 loc) · 1.88 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
#if 0
#include <atomic>
struct qnode {
std::atomic<qnode *> next;
std::atomic<bool> wait;
};
class MCSLock
{
private:
std::atomic<qnode *> _tail;
public:
MCSLock() : _tail(nullptr){};
~MCSLock(){};
void lock(qnode *p)
{
p->next.store(nullptr, std::memory_order_relaxed);
p->wait.store(true, std::memory_order_relaxed);
// exchange _tail with p, return old value of _tail
qnode *prev = _tail.exchange(p, std::memory_order_acquire);
// append p to list if list is non-empty and wait until p is head of list
if (prev != nullptr) {
prev->next.store(p, std::memory_order_relaxed);
while (p->wait.load(std::memory_order_relaxed)) {
// yield/sleep, otherwise does not scale if num_threads > hw_threads
// std::this_thread::yield();
}
}
std::atomic_thread_fence(std::memory_order_acq_rel);
}
// lock can be acquired only when p is head of list
// => release is only called when p is head of list
void unlock(qnode *p)
{
qnode *succ = p->next.load(std::memory_order_release);
if (succ == nullptr) {
qnode *old_p = p; // need to keep p
if (_tail.compare_exchange_strong(old_p,
nullptr,
std::memory_order_relaxed,
std::memory_order_relaxed)) {
// _tail was p and is now nullptr
return;
}
// another thread changed _tail (new qnode enters queue)
// wait until other thread has appended his qnode!
do {
succ = p->next.load(std::memory_order_relaxed);
} while (succ == nullptr);
}
succ->wait.store(false, std::memory_order_relaxed);
}
};
#endif