-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy paththread_safe.cpp
More file actions
76 lines (68 loc) · 1.75 KB
/
Copy paththread_safe.cpp
File metadata and controls
76 lines (68 loc) · 1.75 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
// Demonstrates §7.1 of docs/multithreading.md: per-method locking is NOT
// enough — `top()` + `pop()` as two calls lets two threads observe the same
// element. The fix is an API change: combine the read and the modification
// into one atomic step (and drop `top()` entirely).
#include <iostream>
#include <mutex>
#include <optional>
#include <thread>
#include <vector>
template <typename T> class BrokenStack {
public:
T top() {
std::scoped_lock l(mu_);
return data_.back();
}
void pop() {
std::scoped_lock l(mu_);
data_.pop_back();
}
void push(T x) {
std::scoped_lock l(mu_);
data_.push_back(std::move(x));
}
bool empty() {
std::scoped_lock l(mu_);
return data_.empty();
}
private:
std::mutex mu_;
std::vector<T> data_;
};
template <typename T> class Stack {
public:
// Read and modify in one critical section. optional<T> handles "empty"
// without throwing.
std::optional<T> pop() {
std::scoped_lock l(mu_);
if (data_.empty())
return std::nullopt;
T v = std::move(data_.back());
data_.pop_back();
return v;
}
void push(T x) {
std::scoped_lock l(mu_);
data_.push_back(std::move(x));
}
private:
std::mutex mu_;
std::vector<T> data_;
};
int main() {
Stack<int> s;
for (int i = 0; i < 100; ++i)
s.push(i);
{
std::vector<std::jthread> consumers;
for (int i = 0; i < 4; ++i)
consumers.emplace_back([&] {
while (auto v = s.pop())
(void)*v; // each value popped by exactly one thread
});
}
std::cout << "all 100 values popped exactly once across 4 threads\n";
// BrokenStack is here so the type-name appears in the build and the
// reader can compare; we don't exercise the race deliberately.
(void)sizeof(BrokenStack<int>);
}