-
Notifications
You must be signed in to change notification settings - Fork 3
/
barrier.h
83 lines (66 loc) · 1.74 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
#ifndef CONCURRENCYTS_BARRIER_H
#define CONCURRENCYTS_BARRIER_H
#define __cpp_lib_experimental_barrier 201505
#include <condition_variable>
#include <mutex>
namespace concurrencyts {
template <typename T>
class barrier_base {
public:
typedef int(*compl_func)();
barrier_base(size_t count) : max_count{count}, count{count}, released_count{0} {}
void arrive_and_wait() {
std::unique_lock<std::mutex> ul{lock};
allow.wait(ul, [this]()->bool { return count > 0; });
if (--count == 0) {
ul.unlock();
auto ffunc = static_cast<T*>(this)->final_func();
if (ffunc) {
// run the completion block
auto tmp_count = ffunc();
if (tmp_count >= 0) {
// readjust max_count for next phase of barrier.
max_count = tmp_count;
}
}
// release all waiting threads
done.notify_all();
} else {
done.wait(ul, [this]()->bool { return count == 0; });
ul.unlock();
}
ul.lock();
if (++released_count == max_count) {
count = max_count;
released_count = 0;
ul.unlock();
// allow all waiting threads
allow.notify_all();
}
}
private:
size_t max_count;
std::mutex lock;
std::condition_variable allow;
std::condition_variable done;
size_t count;
size_t released_count;
};
class barrier : public barrier_base<barrier> {
public:
barrier(size_t count) : barrier_base{count} {}
compl_func final_func() {
return nullptr;
}
};
class flex_barrier : public barrier_base<flex_barrier> {
public:
flex_barrier(size_t count, compl_func fnl_func) : barrier_base{count}, fnl_func{fnl_func} {}
compl_func final_func() {
return fnl_func;
}
private:
compl_func fnl_func;
};
}
#endif /* CONCURRENCYTS_BARRIER_H */