userver: userver/engine/shared_mutex.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
shared_mutex.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/engine/shared_mutex.hpp
4/// @brief @copybrief engine::SharedMutex
5
6#include <userver/engine/condition_variable.hpp>
7#include <userver/engine/mutex.hpp>
8#include <userver/engine/semaphore.hpp>
9
10USERVER_NAMESPACE_BEGIN
11
12namespace engine {
13
14/// @ingroup userver_concurrency
15///
16/// @brief std::shared_mutex replacement for asynchronous tasks
17///
18/// ## Example usage:
19///
20/// @snippet engine/shared_mutex_test.cpp Sample engine::SharedMutex usage
21///
22/// @see @ref scripts/docs/en/userver/synchronization.md
23class SharedMutex final {
24 public:
25 SharedMutex();
26 ~SharedMutex() = default;
27
28 SharedMutex(const SharedMutex&) = delete;
29 SharedMutex(SharedMutex&&) = delete;
30 SharedMutex& operator=(const SharedMutex&) = delete;
31 SharedMutex& operator=(SharedMutex&&) = delete;
32
33 void lock();
34 void unlock();
35
36 bool try_lock();
37
38 template <typename Rep, typename Period>
39 bool try_lock_for(const std::chrono::duration<Rep, Period>&);
40
41 template <typename Clock, typename Duration>
42 bool try_lock_until(const std::chrono::time_point<Clock, Duration>&);
43
44 bool try_lock_until(Deadline deadline);
45
46 void lock_shared();
47 void unlock_shared();
48 bool try_lock_shared();
49
50 template <typename Rep, typename Period>
51 bool try_lock_shared_for(const std::chrono::duration<Rep, Period>&);
52
53 template <typename Clock, typename Duration>
54 bool try_lock_shared_until(const std::chrono::time_point<Clock, Duration>&);
55
56 bool try_lock_shared_until(Deadline deadline);
57
58 private:
59 bool HasWaitingWriter() const noexcept;
60
61 bool WaitForNoWaitingWriters(Deadline deadline);
62
63 void DecWaitingWriters();
64
65 /* Semaphore can be get by 1 or by SIZE_MAX.
66 * 1 = reader, SIZE_MAX = writer.
67 *
68 * Three possible cases:
69 * 1) semaphore is free
70 * 2) there are readers in critical section (any count)
71 * 3) there is a single writer in critical section
72 */
73 Semaphore semaphore_;
74
75 /* Readers don't try to hold semaphore_ if there is at least one
76 * waiting writer => writers don't starve.
77 */
78 std::atomic_size_t waiting_writers_count_;
79 Mutex waiting_writers_count_mutex_;
80 ConditionVariable waiting_writers_count_cv_;
81};
82
83template <typename Rep, typename Period>
84bool SharedMutex::try_lock_for(
85 const std::chrono::duration<Rep, Period>& duration) {
86 return try_lock_until(Deadline::FromDuration(duration));
87}
88
89template <typename Rep, typename Period>
90bool SharedMutex::try_lock_shared_for(
91 const std::chrono::duration<Rep, Period>& duration) {
92 return try_lock_shared_until(Deadline::FromDuration(duration));
93}
94
95template <typename Clock, typename Duration>
96bool SharedMutex::try_lock_until(
97 const std::chrono::time_point<Clock, Duration>& until) {
98 return try_lock_until(Deadline::FromTimePoint(until));
99}
100
101template <typename Clock, typename Duration>
102bool SharedMutex::try_lock_shared_until(
103 const std::chrono::time_point<Clock, Duration>& until) {
104 return try_lock_shared_until(Deadline::FromTimePoint(until));
105}
106
107} // namespace engine
108
109USERVER_NAMESPACE_END