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 { 79 std::unique_lock<mutex> lk(this->m_mtx); 80 m_res.emplace(value); 81 } 82 this->m_cv.notify_all(); 83 } 84 set_valueshared_state85 void set_value(R&& value) noexcept 86 { 87 { 88 std::unique_lock<mutex> lk(this->m_mtx); 89 m_res.emplace(std::move(value)); 90 } 91 this->m_cv.notify_all(); 92 } 93 getshared_state94 R& get() noexcept 95 { 96 std::unique_lock lk(this->m_mtx); 97 this->wait_(lk); 98 return m_res.value(); 99 } 100 has_valueshared_state101 bool has_value() const noexcept 102 { 103 return m_res.has_value(); 104 } 105 106 private: 107 std::optional<R> m_res; 108 }; 109 110 template <> 111 struct shared_state<void> : public shared_state_base<shared_state<void>> { 112 void set_value() noexcept 113 { 114 { 115 std::unique_lock<mutex> lk(this->m_mtx); 116 m_hasValue = true; 117 } 118 this->m_cv.notify_all(); 119 } 120 121 void get() noexcept 122 { 123 std::unique_lock lk(this->m_mtx); 124 this->wait_(lk); 125 } 126 127 bool has_value() const noexcept 128 { 129 return m_hasValue; 130 } 131 132 private: 133 bool m_hasValue {false}; 134 }; 135 }; // namespace detail 136 137 template <typename R> 138 class future : private non_copyable { 139 template <typename> 140 friend struct promise; 141 142 template <typename> 143 friend struct packaged_task; 144 145 public: 146 explicit future(const std::shared_ptr<detail::shared_state<R>>& state) noexcept : m_state(state) 147 { 148 } 149 150 future() noexcept = default; 151 152 future(future&& fut) noexcept 153 { 154 swap(fut); 155 } 156 future& operator=(future&& fut) noexcept 157 { 158 if (this != &fut) { 159 future tmp(std::move(fut)); 160 swap(tmp); 161 } 162 return *this; 163 } 164 165 bool valid() const noexcept 166 { 167 return m_state != nullptr; 168 } 169 170 R get() noexcept 171 { 172 auto tmp = std::move(m_state); 173 if constexpr(!std::is_void_v<R>) { 174 return std::move(tmp->get()); 175 } else { 176 return tmp->get(); 177 } 178 } 179 180 template <typename Rep, typename Period> 181 future_status wait_for(const std::chrono::duration<Rep, Period>& waitTime) const noexcept 182 { 183 return m_state->wait_for(waitTime); 184 } 185 186 template <typename Clock, typename Duration> 187 future_status wait_until(const std::chrono::time_point<Clock, Duration>& tp) const noexcept 188 { 189 return m_state->wait_until(tp); 190 } 191 192 void wait() const noexcept 193 { 194 m_state->wait(); 195 } 196 197 void swap(future<R>& rhs) noexcept 198 { 199 std::swap(m_state, rhs.m_state); 200 } 201 202 private: 203 std::shared_ptr<detail::shared_state<R>> m_state; 204 }; 205 206 template <typename R> 207 struct promise : private non_copyable { 208 promise() noexcept : m_state {std::make_shared<detail::shared_state<R>>()} 209 { 210 } 211 promise(promise&& p) noexcept 212 { 213 swap(p); 214 } 215 promise& operator=(promise&& p) noexcept 216 { 217 if (this != &p) { 218 promise tmp(std::move(p)); 219 swap(tmp); 220 } 221 return *this; 222 } 223 224 void set_value(const R& value) noexcept 225 { 226 m_state->set_value(value); 227 } 228 229 void set_value(R&& value) noexcept 230 { 231 m_state->set_value(std::move(value)); 232 } 233 234 future<R> get_future() noexcept 235 { 236 return future<R> {m_state}; 237 } 238 239 void swap(promise<R>& rhs) noexcept 240 { 241 std::swap(m_state, rhs.m_state); 242 } 243 244 private: 245 std::shared_ptr<detail::shared_state<R>> m_state; 246 }; 247 248 template <> 249 struct promise<void> : private non_copyable { 250 promise() noexcept : m_state {std::make_shared<detail::shared_state<void>>()} 251 { 252 } 253 promise(promise&& p) noexcept 254 { 255 swap(p); 256 } 257 promise& operator=(promise&& p) noexcept 258 { 259 if (this != &p) { 260 promise tmp(std::move(p)); 261 swap(tmp); 262 } 263 return *this; 264 } 265 266 void set_value() noexcept 267 { 268 m_state->set_value(); 269 } 270 271 future<void> get_future() noexcept 272 { 273 return future<void> {m_state}; 274 } 275 276 void swap(promise<void>& rhs) noexcept 277 { 278 std::swap(m_state, rhs.m_state); 279 } 280 281 private: 282 std::shared_ptr<detail::shared_state<void>> m_state; 283 }; 284 285 template <typename F> 286 struct packaged_task; 287 288 template <typename R, typename... Args> 289 struct packaged_task<R(Args...)> { 290 packaged_task() noexcept = default; 291 292 packaged_task(const packaged_task& pt) noexcept 293 { 294 m_fn = pt.m_fn; 295 m_state = pt.m_state; 296 } 297 298 packaged_task(packaged_task&& pt) noexcept 299 { 300 swap(pt); 301 } 302 303 packaged_task& operator=(packaged_task&& pt) noexcept 304 { 305 if (this != &pt) { 306 packaged_task tmp(std::move(pt)); 307 swap(tmp); 308 } 309 return *this; 310 } 311 312 template <typename F> 313 explicit packaged_task(F&& f) noexcept 314 : m_fn {std::forward<F>(f)}, m_state {std::make_shared<detail::shared_state<R>>()} 315 { 316 } 317 318 bool valid() const noexcept 319 { 320 return bool(m_fn) && m_state != nullptr; 321 } 322 323 future<R> get_future() noexcept 324 { 325 return future<R> {m_state}; 326 } 327 328 void operator()(Args... args) 329 { 330 if constexpr(!std::is_void_v<R>) { 331 m_state->set_value(m_fn(std::forward<Args>(args)...)); 332 } else { 333 m_fn(std::forward<Args>(args)...); 334 m_state->set_value(); 335 } 336 } 337 338 void swap(packaged_task& pt) noexcept 339 { 340 std::swap(m_fn, pt.m_fn); 341 std::swap(m_state, pt.m_state); 342 } 343 344 private: 345 std::function<R(Args...)> m_fn; 346 std::shared_ptr<detail::shared_state<R>> m_state; 347 }; 348 349 template <typename F, typename... Args> 350 future<std::invoke_result_t<std::decay_t<F>, std::decay_t<Args>...>> async(F&& f, Args&& ... args) 351 { 352 using R = std::invoke_result_t<std::decay_t<F>, std::decay_t<Args>...>; 353 packaged_task<R(std::decay_t<Args>...)> pt {std::forward<F>(f)}; 354 auto fut {pt.get_future()}; 355 auto th = ffrt::thread(std::move(pt), std::forward<Args>(args)...); 356 th.detach(); 357 return fut; 358 } 359 } // namespace ffrt 360 #endif 361