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