blob: 351d5ba79f027688a7610c47821ef959044cecd7 (
plain)
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
|
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
#pragma once
#include <list>
#include <mutex>
/*
Keep a history of item values so that readers can dereference the pointer to
the latest value and continue using it as long as they want. This container
is only appropriate for values that are updated a handful of times over their
total lifetime.
There is a prune() method to throw out old values, but it should only be used
if the caller has some way of knowing all readers are done.
*/
template<class T>
class mutable_item_history {
private:
std::mutex lock;
std::list<T> history;
T *current = nullptr;
public:
mutable_item_history() {
history.emplace_back(T());
current = &history.back();
}
// readers are lock-free
const T& operator*() const {
return *current;
}
const T *operator->() const {
return current;
}
// non-const variants (be careful!)
T& operator*() {
return *current;
}
T *operator->() {
return current;
}
// writes are serialized
const T& operator=(const T& other) {
std::lock_guard l(lock);
history.push_back(other);
current = &history.back();
return *current;
}
void prune() {
// note: this is not necessarily thread-safe wrt readers
std::lock_guard l(lock);
while (history.size() > 1) {
history.pop_front();
}
}
};
template<class T>
class safe_item_history {
private:
std::mutex lock;
std::list<T> history;
T *current = nullptr;
public:
safe_item_history() {
history.emplace_back(T());
current = &history.back();
}
// readers are lock-free
const T& operator*() const {
return *current;
}
const T *operator->() const {
return current;
}
// writes are serialized
const T& operator=(const T& other) {
std::lock_guard l(lock);
history.push_back(other);
current = &history.back();
return *current;
}
void prune() {
// note: this is not necessarily thread-safe wrt readers
std::lock_guard l(lock);
while (history.size() > 1) {
history.pop_front();
}
}
};
|