Flutter Engine
 
Loading...
Searching...
No Matches
thread.h
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef FLUTTER_IMPELLER_BASE_THREAD_H_
6#define FLUTTER_IMPELLER_BASE_THREAD_H_
7
8#include <chrono>
9#include <condition_variable>
10#include <functional>
11#include <memory>
12#include <mutex>
13#include <shared_mutex>
14#include <thread>
15
17
18namespace impeller {
19
21
22class IPLR_CAPABILITY("mutex") Mutex {
23 public:
24 Mutex() = default;
25
26 ~Mutex() = default;
27
28 void Lock() IPLR_ACQUIRE() { mutex_.lock(); }
29
30 void Unlock() IPLR_RELEASE() { mutex_.unlock(); }
31
32 private:
33 friend class ConditionVariable;
34
35 std::mutex mutex_;
36
37 Mutex(const Mutex&) = delete;
38
39 Mutex(Mutex&&) = delete;
40
41 Mutex& operator=(const Mutex&) = delete;
42
43 Mutex& operator=(Mutex&&) = delete;
44};
45
46class IPLR_CAPABILITY("mutex") RWMutex {
47 public:
48 RWMutex() = default;
49
50 ~RWMutex() = default;
51
52 void LockWriter() IPLR_ACQUIRE() { mutex_.lock(); }
53
54 void UnlockWriter() IPLR_RELEASE() { mutex_.unlock(); }
55
56 void LockReader() IPLR_ACQUIRE_SHARED() { mutex_.lock_shared(); }
57
58 void UnlockReader() IPLR_RELEASE_SHARED() { mutex_.unlock_shared(); }
59
60 private:
61 std::shared_mutex mutex_;
62
63 RWMutex(const RWMutex&) = delete;
64
65 RWMutex(RWMutex&&) = delete;
66
67 RWMutex& operator=(const RWMutex&) = delete;
68
69 RWMutex& operator=(RWMutex&&) = delete;
70};
71
73 public:
74 explicit Lock(Mutex& mutex) IPLR_ACQUIRE(mutex) : mutex_(mutex) {
75 mutex_.Lock();
76 }
77
78 ~Lock() IPLR_RELEASE() { mutex_.Unlock(); }
79
80 private:
81 Mutex& mutex_;
82
83 Lock(const Lock&) = delete;
84
85 Lock(Lock&&) = delete;
86
87 Lock& operator=(const Lock&) = delete;
88
89 Lock& operator=(Lock&&) = delete;
90};
91
93 public:
94 explicit ReaderLock(RWMutex& mutex) IPLR_ACQUIRE_SHARED(mutex)
95 : mutex_(mutex) {
96 mutex_.LockReader();
97 }
98
99 ~ReaderLock() IPLR_RELEASE() { mutex_.UnlockReader(); }
100
101 private:
102 RWMutex& mutex_;
103
104 ReaderLock(const ReaderLock&) = delete;
105
106 ReaderLock(ReaderLock&&) = delete;
107
108 ReaderLock& operator=(const ReaderLock&) = delete;
109
110 ReaderLock& operator=(ReaderLock&&) = delete;
111};
112
114 public:
115 explicit WriterLock(RWMutex& mutex) IPLR_ACQUIRE(mutex) : mutex_(mutex) {
116 mutex_.LockWriter();
117 }
118
119 ~WriterLock() IPLR_RELEASE() { mutex_.UnlockWriter(); }
120
121 private:
122 RWMutex& mutex_;
123
124 WriterLock(const WriterLock&) = delete;
125
126 WriterLock(WriterLock&&) = delete;
127
128 WriterLock& operator=(const WriterLock&) = delete;
129
130 WriterLock& operator=(WriterLock&&) = delete;
131};
132
133//------------------------------------------------------------------------------
134/// @brief A condition variable exactly similar to the one in libcxx with
135/// two major differences:
136///
137/// * On the Wait, WaitFor, and WaitUntil calls, static analysis
138/// annotation are respected.
139/// * There is no ability to wait on a condition variable and also
140/// be susceptible to spurious wakes. This is because the
141/// predicate is mandatory.
142///
144 public:
145 ConditionVariable() = default;
146
148
150
152
153 void NotifyOne() { cv_.notify_one(); }
154
155 void NotifyAll() { cv_.notify_all(); }
156
157 using Predicate = std::function<bool()>;
158
159 //----------------------------------------------------------------------------
160 /// @brief Atomically unlocks the mutex and waits on the condition
161 /// variable up to a specified time point. Lock will be reacquired
162 /// when the wait exits. Spurious wakes may happen before the time
163 /// point is reached. In such cases the predicate is invoked and
164 /// it must return `false` for the wait to continue. The predicate
165 /// will be invoked with the mutex locked.
166 ///
167 /// @note Since the predicate is invoked with the mutex locked, if it
168 /// accesses other guarded resources, the predicate itself must be
169 /// decorated with the IPLR_REQUIRES directive. For instance,
170 ///
171 /// ```c++
172 /// [] () IPLR_REQUIRES(mutex) {
173 /// return my_guarded_resource.should_stop_waiting;
174 /// }
175 /// ```
176 ///
177 /// @param mutex The mutex.
178 /// @param[in] time_point The time point to wait to.
179 /// @param[in] should_stop_waiting The predicate invoked on spurious wakes.
180 /// Must return false for the wait to
181 /// continue.
182 ///
183 /// @tparam Clock The clock type.
184 /// @tparam Duration The duration type.
185 ///
186 /// @return The value of the predicate at the end of the wait.
187 ///
188 template <class Clock, class Duration>
189 bool WaitUntil(Mutex& mutex,
190 const std::chrono::time_point<Clock, Duration>& time_point,
191 const Predicate& should_stop_waiting) IPLR_REQUIRES(mutex) {
192 std::unique_lock lock(mutex.mutex_, std::adopt_lock);
193 const auto result = cv_.wait_until(lock, time_point, should_stop_waiting);
194 lock.release();
195 return result;
196 }
197
198 //----------------------------------------------------------------------------
199 /// @brief Atomically unlocks the mutex and waits on the condition
200 /// variable for a designated duration. Lock will be reacquired
201 /// when the wait exits. Spurious wakes may happen before the time
202 /// point is reached. In such cases the predicate is invoked and
203 /// it must return `false` for the wait to continue. The predicate
204 /// will be invoked with the mutex locked.
205 ///
206 /// @note Since the predicate is invoked with the mutex locked, if it
207 /// accesses other guarded resources, the predicate itself must be
208 /// decorated with the IPLR_REQUIRES directive. For instance,
209 ///
210 /// ```c++
211 /// [] () IPLR_REQUIRES(mutex) {
212 /// return my_guarded_resource.should_stop_waiting;
213 /// }
214 /// ```
215 ///
216 /// @param mutex The mutex.
217 /// @param[in] duration The duration to wait for.
218 /// @param[in] should_stop_waiting The predicate invoked on spurious wakes.
219 /// Must return false for the wait to
220 /// continue.
221 ///
222 /// @tparam Representation The duration representation type.
223 /// @tparam Period The duration period type.
224 ///
225 /// @return The value of the predicate at the end of the wait.
226 ///
227 template <class Representation, class Period>
228 bool WaitFor(Mutex& mutex,
229 const std::chrono::duration<Representation, Period>& duration,
230 const Predicate& should_stop_waiting) IPLR_REQUIRES(mutex) {
231 return WaitUntil(mutex, std::chrono::steady_clock::now() + duration,
232 should_stop_waiting);
233 }
234
235 //----------------------------------------------------------------------------
236 /// @brief Atomically unlocks the mutex and waits on the condition
237 /// variable indefinitely till the predicate determines that the
238 /// wait must end. Lock will be reacquired when the wait exits.
239 /// Spurious wakes may happen before the time point is reached. In
240 /// such cases the predicate is invoked and it must return `false`
241 /// for the wait to continue. The predicate will be invoked with
242 /// the mutex locked.
243 ///
244 /// @note Since the predicate is invoked with the mutex locked, if it
245 /// accesses other guarded resources, the predicate itself must be
246 /// decorated with the IPLR_REQUIRES directive. For instance,
247 ///
248 /// ```c++
249 /// [] () IPLR_REQUIRES(mutex) {
250 /// return my_guarded_resource.should_stop_waiting;
251 /// }
252 /// ```
253 ///
254 /// @param mutex The mutex
255 /// @param[in] should_stop_waiting The should stop waiting
256 ///
257 void Wait(Mutex& mutex, const Predicate& should_stop_waiting)
258 IPLR_REQUIRES(mutex) {
259 std::unique_lock lock(mutex.mutex_, std::adopt_lock);
260 cv_.wait(lock, should_stop_waiting);
261 lock.release();
262 }
263
264 private:
265 std::condition_variable cv_;
266};
267
268} // namespace impeller
269
270#endif // FLUTTER_IMPELLER_BASE_THREAD_H_
A condition variable exactly similar to the one in libcxx with two major differences:
Definition thread.h:143
ConditionVariable & operator=(const ConditionVariable &)=delete
bool WaitFor(Mutex &mutex, const std::chrono::duration< Representation, Period > &duration, const Predicate &should_stop_waiting) IPLR_REQUIRES(mutex)
Atomically unlocks the mutex and waits on the condition variable for a designated duration....
Definition thread.h:228
bool WaitUntil(Mutex &mutex, const std::chrono::time_point< Clock, Duration > &time_point, const Predicate &should_stop_waiting) IPLR_REQUIRES(mutex)
Atomically unlocks the mutex and waits on the condition variable up to a specified time point....
Definition thread.h:189
ConditionVariable(const ConditionVariable &)=delete
void Wait(Mutex &mutex, const Predicate &should_stop_waiting) IPLR_REQUIRES(mutex)
Atomically unlocks the mutex and waits on the condition variable indefinitely till the predicate dete...
Definition thread.h:257
std::function< bool()> Predicate
Definition thread.h:157
~Lock() IPLR_RELEASE()
Definition thread.h:78
Lock(Mutex &mutex) IPLR_ACQUIRE(mutex)
Definition thread.h:74
~ReaderLock() IPLR_RELEASE()
Definition thread.h:99
ReaderLock(RWMutex &mutex) IPLR_ACQUIRE_SHARED(mutex)
Definition thread.h:94
~WriterLock() IPLR_RELEASE()
Definition thread.h:119
WriterLock(RWMutex &mutex) IPLR_ACQUIRE(mutex)
Definition thread.h:115
#define IPLR_REQUIRES(...)
#define IPLR_ACQUIRE_SHARED(...)
#define IPLR_ACQUIRE(...)
#define IPLR_RELEASE(...)
#define IPLR_CAPABILITY(x)
#define IPLR_RELEASE_SHARED(...)
#define IPLR_SCOPED_CAPABILITY