-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathDataProtector.h
97 lines (79 loc) · 2.11 KB
/
DataProtector.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
#include <atomic>
#include <unistd.h>
template<int Nr>
class DataProtector {
struct alignas(64) Entry {
std::atomic<int> _count;
};
Entry* _list;
static std::atomic<int> _last;
static thread_local int _mySlot;
public:
// A class to automatically unuse the DataProtector:
class UnUser {
DataProtector* _prot;
int _id;
public:
UnUser (DataProtector* p, int i) : _prot(p), _id(i) {
}
~UnUser () {
if (_prot != nullptr) {
_prot->unUse(_id);
}
}
// A move constructor
UnUser (UnUser&& that) : _prot(that._prot), _id(that._id) {
// Note that return value optimization will usually avoid
// this move constructor completely. However, it has to be
// present for the program to compile.
that._prot = nullptr;
}
// Explicitly delete the others:
UnUser (UnUser const& that) = delete;
UnUser& operator= (UnUser const& that) = delete;
UnUser& operator= (UnUser&& that) = delete;
UnUser () = delete;
};
DataProtector () : _list(nullptr) {
_list = new Entry[Nr];
// Just to be sure:
for (size_t i = 0; i < Nr; i++) {
_list[i]._count = 0;
}
}
~DataProtector () {
delete[] _list;
}
UnUser use () {
int id = getMyId();
_list[id]._count++; // this is implicitly using memory_order_seq_cst
return UnUser(this, id); // return value optimization!
}
void scan () {
for (size_t i = 0; i < Nr; i++) {
while (_list[i]._count > 0) {
usleep(250);
}
}
}
private:
void unUse (int id) {
_list[id]._count--; // this is implicitly using memory_order_seq_cst
}
int getMyId () {
int id = _mySlot;
if (id >= 0) {
return id;
}
while (true) {
int newId = _last + 1;
if (newId >= Nr) {
newId = 0;
}
if (_last.compare_exchange_strong(id, newId)) {
_mySlot = newId;
return newId;
}
}
}
};