-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathExample_RecursiveMutex.cpp
More file actions
160 lines (117 loc) · 4.02 KB
/
Example_RecursiveMutex.cpp
File metadata and controls
160 lines (117 loc) · 4.02 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
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// ===========================================================================
// Examples_RecursiveMutex.cpp // std::recursive_mutex
// ===========================================================================
#include <algorithm>
#include <cstddef>
#include <iostream>
#include <mutex>
#include <thread>
// https://medium.com/@simontoth/daily-bit-e-of-c-std-recursive-mutex-dd9b84f38f8d
namespace Recursive_Mutex_Example
{
constexpr std::size_t BucketSize = 4;
class NonRecursive
{
private:
std::mutex m_mutex;
std::unique_ptr<std::size_t[]> m_data;
std::size_t m_size;
std::size_t m_capacity;
public:
NonRecursive() : m_size{}, m_capacity{} {}
void push_back(std::size_t value) {
std::unique_lock lock{ m_mutex };
// we already hold 'm_mutex', so we cannot call reserve()
if (m_size == m_capacity) {
allocate(m_capacity == 0 ? BucketSize : m_capacity * 2);
}
m_data[m_size++] = value;
}
void reserve(std::size_t capacity) {
std::unique_lock lock{ m_mutex };
allocate(capacity);
}
void print() {
std::unique_lock lock{ m_mutex };
for (std::size_t i{}; i != m_size; ++i) {
std::cout << m_data[i] << ' ';
}
std::cout << std::endl;
}
private:
// allocate expects m_mutex to be held by the caller
void allocate(std::size_t capacity) {
std::cout << "allocating " << capacity << std::endl;
std::unique_ptr<std::size_t[]> data{ std::make_unique<std::size_t[]>(capacity) };
std::size_t newSize{ std::min(m_size, capacity) };
std::copy(
m_data.get(),
m_data.get() + newSize,
data.get()
);
m_data = std::move(data);
m_capacity = capacity;
m_size = newSize;
}
};
class Recursive
{
private:
std::recursive_mutex recursive_mutex;
std::unique_ptr<std::size_t[]> m_data;
std::size_t m_size;
std::size_t m_capacity;
public:
Recursive() : m_size{}, m_capacity{} {}
void push_back(std::size_t value) {
std::unique_lock lock{ recursive_mutex };
// holding a recursive mutex multiple times is fine
if (m_size == m_capacity) {
reserve(m_capacity == 0 ? BucketSize : m_capacity * 2);
}
m_data[m_size++] = value;
}
void reserve(std::size_t capacity) {
std::unique_lock lock{ recursive_mutex };
std::cout << "allocating " << capacity << std::endl;
std::unique_ptr<std::size_t[]> data{ std::make_unique<std::size_t[]>(capacity) };
std::size_t newSize{ std::min(m_size, capacity) };
std::copy(
m_data.get(),
m_data.get() + newSize,
data.get()
);
m_data = std::move(data);
m_capacity = capacity;
m_size = newSize;
}
void print() {
std::unique_lock lock{ recursive_mutex };
for (std::size_t i{}; i != m_size; ++i) {
std::cout << m_data[i] << ' ';
}
std::cout << std::endl;
}
};
}
void example_recursive_mutex()
{
using namespace Recursive_Mutex_Example;
NonRecursive non{};
for (std::size_t i{}; i != 18; i++) {
non.push_back(i+1);
}
non.print();
non.reserve(2);
non.print();
Recursive rec{};
for (std::size_t i{}; i != 18; i++) {
rec.push_back(100 + i+1);
}
rec.print();
rec.reserve(2);
rec.print();
}
// ===========================================================================
// End-of-File
// ===========================================================================