/
barrier.h
114 lines (99 loc) · 2.51 KB
/
barrier.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
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
#ifndef __BARRIER_H__
#define __BARRIER_H__
#include <atomic>
#include <cstdlib>
#include <omp.h>
struct CoreCacheLine{
std::atomic<int> signalLeft;
std::atomic<int> signalRight;
char padding[64-2*sizeof(std::atomic<int>)];
};
class Barrier{
private:
CoreCacheLine *messages;
size_t nThreads;
inline void sendRight(size_t threadId){
while(messages[threadId].signalRight.load(std::memory_order_relaxed) != 0);
messages[threadId].signalRight.store(1, std::memory_order_relaxed);
while(messages[threadId].signalRight.load(std::memory_order_relaxed) != 2);
messages[threadId].signalRight.store(0, std::memory_order_relaxed);
}
inline void receiveLeft(size_t threadId){
while(messages[threadId-1].signalRight.load(std::memory_order_relaxed) != 1);
messages[threadId-1].signalRight.store(2, std::memory_order_relaxed);
}
inline void sendLeft(size_t threadId){
int ex;
do{
ex = 0;
}
while(!messages[threadId].signalLeft.compare_exchange_weak(ex, 1, std::memory_order_relaxed));
do{
ex = 2;
}
while(!messages[threadId].signalLeft.compare_exchange_weak(ex, 0, std::memory_order_relaxed));
}
inline void receiveRight(size_t threadId){
int ex;
do{
ex = 1;
}
while(!messages[threadId+1].signalLeft.compare_exchange_weak(ex, 2, std::memory_order_relaxed));
}
public:
Barrier(size_t n = 0){
nThreads = n;
messages = new CoreCacheLine[nThreads];
for(size_t i=0; i<nThreads; ++i){
messages[i].signalLeft.store(0);
messages[i].signalRight.store(0);
}
}
void barrier(size_t threadId){
if (threadId == 0){
sendRight(threadId);
}
else{
receiveLeft(threadId);
if (threadId != nThreads - 1){
sendRight(threadId);
}
}
if (threadId == nThreads-1){
sendLeft(threadId);
}
else{
receiveRight(threadId);
if (threadId != 0){
sendLeft(threadId);
}
}
}
inline void barrier(){
barrier(omp_get_thread_num());
}
};
class BarrierCounter{
private:
std::atomic<int> entered;
std::atomic<int> leaved;
size_t nThreads;
public:
BarrierCounter(size_t n){
nThreads = n;
entered.store(0);
leaved.store(0);
}
inline void barrier(size_t threadId){
while(leaved.load(std::memory_order_relaxed));
entered.fetch_add(1, std::memory_order_relaxed);
while(entered.load(std::memory_order_relaxed) < nThreads);
leaved.fetch_add(1, std::memory_order_relaxed);
while(leaved.load(std::memory_order_relaxed) < nThreads);
int old = entered.fetch_add(-1, std::memory_order_relaxed);
if (old == 1){
leaved.store(0, std::memory_order_relaxed);
}
}
};
#endif