1 /* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 #ifndef FFRT_API_CPP_FUTURE_H 16 #define FFRT_API_CPP_FUTURE_H 17 #include <memory> 18 #include <optional> 19 #include <chrono> 20 #include "cpp/condition_variable.h" 21 #include "thread.h" 22 23 namespace ffrt { 24 struct non_copyable { 25 protected: 26 non_copyable() = default; 27 ~non_copyable() = default; 28 non_copyable(const non_copyable&) = delete; 29 non_copyable& operator=(const non_copyable&) = delete; 30 }; 31 enum class future_status { ready, timeout, deferred }; 32 33 namespace detail { 34 template <typename Derived> 35 struct shared_state_base : private non_copyable { waitshared_state_base36 void wait() const noexcept 37 { 38 std::unique_lock lk(this->m_mtx); 39 wait_(lk); 40 } 41 42 template <typename Rep, typename Period> wait_forshared_state_base43 future_status wait_for(const std::chrono::duration<Rep, Period>& waitTime) const noexcept 44 { 45 std::unique_lock<mutex> lk(m_mtx); 46 return m_cv.wait_for(lk, waitTime, [this] { return get_derived().has_value(); }) ? future_status::ready : 47 future_status::timeout; 48 } 49 50 template <typename Clock, typename Duration> wait_untilshared_state_base51 future_status wait_until(const std::chrono::time_point<Clock, Duration>& tp) const noexcept 52 { 53 std::unique_lock<mutex> lk(m_mtx); 54 return m_cv.wait_until(lk, tp, [this] { return get_derived().has_value(); }) ? future_status::ready : 55 future_status::timeout; 56 } 57 58 protected: wait_shared_state_base59 void wait_(std::unique_lock<mutex>& lk) const noexcept 60 { 61 m_cv.wait(lk, [this] { return get_derived().has_value(); }); 62 } 63 64 mutable mutex m_mtx; 65 mutable condition_variable m_cv; 66 67 private: get_derivedshared_state_base68 const Derived& get_derived() const 69 { 70 return *static_cast<const Derived*>(this); 71 } 72 }; 73 74 template <typename R> 75 struct shared_state : public shared_state_base<shared_state<R>> { set_valueshared_state76 void set_value(const R& value) noexcept 77 { 78 std::unique_lock<mutex> lk(this->m_mtx); 79 m_res.emplace(value); 80 this->m_cv.notify_all(); 81 } 82 set_valueshared_state83 void set_value(R&& value) noexcept 84 { 85 std::unique_lock<mutex> lk(this->m_mtx); 86 m_res.emplace(std::move(value)); 87 this->m_cv.notify_all(); 88 } 89 getshared_state90 R& get() noexcept 91 { 92 std::unique_lock lk(this->m_mtx); 93 this->wait_(lk); 94 return m_res.value(); 95 } 96 has_valueshared_state97 bool has_value() const noexcept 98 { 99 return m_res.has_value(); 100 } 101 102 private: 103 std::optional<R> m_res; 104 }; 105 106 template <> 107 struct shared_state<void> : public shared_state_base<shared_state<void>> { 108 void set_value() noexcept 109 { 110 std::unique_lock<mutex> lk(this->m_mtx); 111 m_hasValue = true; 112 this->m_cv.notify_all(); 113 } 114 115 void get() noexcept 116 { 117 std::unique_lock lk(this->m_mtx); 118 this->wait_(lk); 119 } 120 121 bool has_value() const noexcept 122 { 123 return m_hasValue; 124 } 125 126 private: 127 bool m_hasValue {false}; 128 }; 129 }; // namespace detail 130 131 template <typename R> 132 class future : private non_copyable { 133 template <typename> 134 friend struct promise; 135 136 template <typename> 137 friend struct packaged_task; 138 139 public: 140 explicit future(const std::shared_ptr<detail::shared_state<R>>& state) noexcept : m_state(state) 141 { 142 } 143 144 future() noexcept = default; 145 146 future(future&& fut) noexcept 147 { 148 swap(fut); 149 } 150 future& operator=(future&& fut) noexcept 151 { 152 if (this != &fut) { 153 future tmp(std::move(fut)); 154 swap(tmp); 155 } 156 return *this; 157 } 158 159 bool valid() const noexcept 160 { 161 return m_state != nullptr; 162 } 163 164 R get() noexcept 165 { 166 auto tmp = std::move(m_state); 167 if constexpr(!std::is_void_v<R>) { 168 return std::move(tmp->get()); 169 } else { 170 return tmp->get(); 171 } 172 } 173 174 template <typename Rep, typename Period> 175 future_status wait_for(const std::chrono::duration<Rep, Period>& waitTime) const noexcept 176 { 177 return m_state->wait_for(waitTime); 178 } 179 180 template <typename Clock, typename Duration> 181 future_status wait_until(const std::chrono::time_point<Clock, Duration>& tp) const noexcept 182 { 183 return m_state->wait_until(tp); 184 } 185 186 void wait() const noexcept 187 { 188 m_state->wait(); 189 } 190 191 void swap(future<R>& rhs) noexcept 192 { 193 std::swap(m_state, rhs.m_state); 194 } 195 196 private: 197 std::shared_ptr<detail::shared_state<R>> m_state; 198 }; 199 200 template <typename R> 201 struct promise : private non_copyable { 202 promise() noexcept : m_state {std::make_shared<detail::shared_state<R>>()} 203 { 204 } 205 promise(promise&& p) noexcept 206 { 207 swap(p); 208 } 209 promise& operator=(promise&& p) noexcept 210 { 211 if (this != &p) { 212 promise tmp(std::move(p)); 213 swap(tmp); 214 } 215 return *this; 216 } 217 218 void set_value(const R& value) noexcept 219 { 220 m_state->set_value(value); 221 } 222 223 void set_value(R&& value) noexcept 224 { 225 m_state->set_value(std::move(value)); 226 } 227 228 future<R> get_future() noexcept 229 { 230 return future<R> {m_state}; 231 } 232 233 void swap(promise<R>& rhs) noexcept 234 { 235 std::swap(m_state, rhs.m_state); 236 } 237 238 private: 239 std::shared_ptr<detail::shared_state<R>> m_state; 240 }; 241 242 template <> 243 struct promise<void> : private non_copyable { 244 promise() noexcept : m_state {std::make_shared<detail::shared_state<void>>()} 245 { 246 } 247 promise(promise&& p) noexcept 248 { 249 swap(p); 250 } 251 promise& operator=(promise&& p) noexcept 252 { 253 if (this != &p) { 254 promise tmp(std::move(p)); 255 swap(tmp); 256 } 257 return *this; 258 } 259 260 void set_value() noexcept 261 { 262 m_state->set_value(); 263 } 264 265 future<void> get_future() noexcept 266 { 267 return future<void> {m_state}; 268 } 269 270 void swap(promise<void>& rhs) noexcept 271 { 272 std::swap(m_state, rhs.m_state); 273 } 274 275 private: 276 std::shared_ptr<detail::shared_state<void>> m_state; 277 }; 278 279 template <typename F> 280 struct packaged_task; 281 282 template <typename R, typename... Args> 283 struct packaged_task<R(Args...)> { 284 packaged_task() noexcept = default; 285 286 packaged_task(const packaged_task& pt) noexcept 287 { 288 m_fn = pt.m_fn; 289 m_state = pt.m_state; 290 } 291 292 packaged_task(packaged_task&& pt) noexcept 293 { 294 swap(pt); 295 } 296 297 packaged_task& operator=(packaged_task&& pt) noexcept 298 { 299 if (this != &pt) { 300 packaged_task tmp(std::move(pt)); 301 swap(tmp); 302 } 303 return *this; 304 } 305 306 template <typename F> 307 explicit packaged_task(F&& f) noexcept 308 : m_fn {std::forward<F>(f)}, m_state {std::make_shared<detail::shared_state<R>>()} 309 { 310 } 311 312 bool valid() const noexcept 313 { 314 return bool(m_fn) && m_state != nullptr; 315 } 316 317 future<R> get_future() noexcept 318 { 319 return future<R> {m_state}; 320 } 321 322 void operator()(Args... args) 323 { 324 if constexpr(!std::is_void_v<R>) { 325 m_state->set_value(m_fn(std::forward<Args>(args)...)); 326 } else { 327 m_fn(std::forward<Args>(args)...); 328 m_state->set_value(); 329 } 330 } 331 332 void swap(packaged_task& pt) noexcept 333 { 334 std::swap(m_fn, pt.m_fn); 335 std::swap(m_state, pt.m_state); 336 } 337 338 private: 339 std::function<R(Args...)> m_fn; 340 std::shared_ptr<detail::shared_state<R>> m_state; 341 }; 342 343 template <typename F, typename... Args> 344 future<std::invoke_result_t<std::decay_t<F>, std::decay_t<Args>...>> async(F&& f, Args&& ... args) 345 { 346 using R = std::invoke_result_t<std::decay_t<F>, std::decay_t<Args>...>; 347 packaged_task<R(std::decay_t<Args>...)> pt {std::forward<F>(f)}; 348 auto fut {pt.get_future()}; 349 auto th = ffrt::thread(std::move(pt), std::forward<Args>(args)...); 350 th.detach(); 351 return fut; 352 } 353 } // namespace ffrt 354 #endif 355