userver
C++ Async Framework
Toggle main menu visibility
Loading...
Searching...
No Matches
variable.hpp
Go to the documentation of this file.
1
#
pragma
once
2
3
/// @file userver/concurrent/variable.hpp
4
/// @brief @copybrief concurrent::Variable
5
6
#
include
<
cstdlib
>
7
#
include
<
mutex
>
8
#
include
<
optional
>
9
#
include
<
shared_mutex
>
// for shared_lock
10
11
#
include
<
userver
/
compiler
/
impl
/
lifetime
.
hpp
>
12
#
include
<
userver
/
engine
/
mutex
.
hpp
>
13
14
USERVER_NAMESPACE_BEGIN
15
16
/// Locking stuff
17
namespace
concurrent
{
18
19
/// Proxy class for locked access to data protected with locking::SharedLock<T>
20
template
<
typename
Lock,
typename
Data>
21
class
LockedPtr final {
22
public
:
23
using
Mutex =
typename
Lock::mutex_type;
24
25
LockedPtr(Mutex& mutex, Data& data)
26
: lock_(mutex),
27
data_(data)
28
{}
29
LockedPtr(Lock&& lock, Data& data)
30
: lock_(std::move(lock)),
31
data_(data)
32
{}
33
34
Data& operator*() & USERVER_IMPL_LIFETIME_BOUND {
return
data_; }
35
const
Data& operator*()
const
& USERVER_IMPL_LIFETIME_BOUND {
return
data_; }
36
37
/// Don't use *tmp for temporary value, store it to variable.
38
Data&
operator
*() && {
return
*GetOnRvalue(); }
39
40
Data* operator->() & USERVER_IMPL_LIFETIME_BOUND {
return
&data_; }
41
const
Data* operator->()
const
& USERVER_IMPL_LIFETIME_BOUND {
return
&data_; }
42
43
/// Don't use tmp-> for temporary value, store it to variable.
44
Data*
operator
->() && {
return
GetOnRvalue(); }
45
46
/// For node-based containers, e.g. `std::unordered_map`, where container access needs to be locked,
47
/// but after that the reference is stable and does not need the lock anymore.
48
Data&
GetUnsafeForStableSubobject
() & {
return
data_; }
49
const
Data& GetUnsafeForStableSubobject()
const
& {
return
data_; }
50
51
/// Don't use *tmp for temporary value, store it to variable.
52
Data&
GetUnsafeForStableSubobject
() && {
return
*GetOnRvalue(); }
53
54
Lock& GetLock() USERVER_IMPL_LIFETIME_BOUND {
return
lock_; }
55
56
private
:
57
const
Data* GetOnRvalue() {
58
static_assert
(!
sizeof
(Data),
"Don't use temporary LockedPtr, store it to a variable"
);
59
std::abort();
60
}
61
62
Lock lock_;
63
Data& data_;
64
};
65
66
/// @ingroup userver_concurrency userver_containers
67
///
68
/// Container for shared data protected with a mutex of any type
69
/// (mutex, shared mutex, etc.).
70
/// ## Example usage:
71
///
72
/// @snippet concurrent/variable_test.cpp Sample concurrent::Variable usage
73
///
74
/// @see @ref scripts/docs/en/userver/synchronization.md
75
template
<
typename
Data,
typename
Mutex = engine::Mutex>
76
class
Variable final {
77
public
:
78
template
<
typename
... Arg>
79
Variable(Arg&&... arg)
80
: data_(std::forward<Arg>(arg)...)
81
{}
82
83
LockedPtr<std::unique_lock<Mutex>, Data> UniqueLock() {
return
{mutex_, data_}; }
84
85
LockedPtr<std::unique_lock<Mutex>,
const
Data> UniqueLock()
const
{
return
{mutex_, data_}; }
86
87
std::optional<LockedPtr<std::unique_lock<Mutex>,
const
Data>> UniqueLock(std::try_to_lock_t)
const
{
88
return
DoUniqueLock(*
this
, std::try_to_lock);
89
}
90
91
std::optional<LockedPtr<std::unique_lock<Mutex>, Data>> UniqueLock(std::try_to_lock_t) {
92
return
DoUniqueLock(*
this
, std::try_to_lock);
93
}
94
95
std::optional<LockedPtr<std::unique_lock<Mutex>,
const
Data>> UniqueLock(std::chrono::milliseconds try_duration
96
)
const
{
97
return
DoUniqueLock(*
this
, try_duration);
98
}
99
100
std::optional<LockedPtr<std::unique_lock<Mutex>, Data>> UniqueLock(std::chrono::milliseconds try_duration) {
101
return
DoUniqueLock(*
this
, try_duration);
102
}
103
104
LockedPtr<std::shared_lock<Mutex>,
const
Data> SharedLock()
const
{
return
{mutex_, data_}; }
105
106
/// Useful for grabbing a reference to an object in a node-based container,
107
/// e.g. `std::unordered_map`. Values must support concurrent modification.
108
LockedPtr<std::shared_lock<Mutex>, Data>
SharedMutableLockUnsafe
() {
return
{mutex_, data_}; }
109
110
LockedPtr<std::lock_guard<Mutex>, Data> Lock() {
return
{mutex_, data_}; }
111
112
LockedPtr<std::lock_guard<Mutex>,
const
Data> Lock()
const
{
return
{mutex_, data_}; }
113
114
/// Get raw mutex. Use with caution. For simple use cases call Lock(),
115
/// UniqueLock(), SharedLock() instead.
116
Mutex&
GetMutexUnsafe
()
const
{
return
mutex_; }
117
118
/// Get raw data. Use with extreme caution, only for cases where it is
119
/// impossible to access data with safe methods (e.g. std::scoped_lock with
120
/// multiple mutexes). For simple use cases call Lock(), UniqueLock(),
121
/// SharedLock() instead.
122
Data&
GetDataUnsafe
() {
return
data_; }
123
124
const
Data& GetDataUnsafe()
const
{
return
data_; }
125
126
private
:
127
mutable
Mutex mutex_;
128
Data data_;
129
130
/// We need this function to work around const/non-const methods. This
131
/// helper accepts concurrent variables as template parameter and thus
132
/// will accept both const and non-const vars. And Data typename will
133
/// resolve to const/non-const accordingly.
134
template
<
typename
VariableType,
typename
... StdUniqueLockArgs>
135
static
auto
DoUniqueLock(VariableType& concurrent_variable, StdUniqueLockArgs&&... args) {
136
std::unique_lock<Mutex> lock(concurrent_variable.mutex_, std::forward<StdUniqueLockArgs>(args)...);
137
return
lock ? std::optional{LockedPtr{std::move(lock), concurrent_variable.data_}} : std::nullopt;
138
}
139
};
140
141
}
// namespace concurrent
142
143
USERVER_NAMESPACE_END
userver
concurrent
variable.hpp
Generated on
for userver by
Doxygen
1.17.0