/* * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file condition_variable.h * * @brief Declares the condition variable interfaces in C++. * * @since 10 * @version 1.0 */ #ifndef FFRT_API_CPP_CONDITION_VARIABLE_H #define FFRT_API_CPP_CONDITION_VARIABLE_H #include <chrono> #include <mutex> #include "mutex.h" #include "c/condition_variable.h" namespace ffrt { enum class cv_status { no_timeout, timeout }; class condition_variable : public ffrt_cond_t { public: condition_variable() { ffrt_cond_init(this, nullptr); } ~condition_variable() noexcept { ffrt_cond_destroy(this); } condition_variable(const condition_variable&) = delete; condition_variable& operator=(const condition_variable&) = delete; template <typename Clock, typename Duration, typename Pred> bool wait_until( std::unique_lock<mutex>& lk, const std::chrono::time_point<Clock, Duration>& tp, Pred&& pred) noexcept { while (!pred()) { if (wait_until(lk, tp) == cv_status::timeout) { return pred(); } } return true; } template <typename Clock, typename Duration> cv_status wait_until(std::unique_lock<mutex>& lk, const std::chrono::time_point<Clock, Duration>& tp) noexcept { return _wait_for(lk, tp - Clock::now()); } template <typename Rep, typename Period> cv_status wait_for(std::unique_lock<mutex>& lk, const std::chrono::duration<Rep, Period>& sleep_time) noexcept { return _wait_for(lk, sleep_time); } template <typename Rep, typename Period, typename Pred> bool wait_for( std::unique_lock<mutex>& lk, const std::chrono::duration<Rep, Period>& sleepTime, Pred&& pred) noexcept { return wait_until(lk, std::chrono::steady_clock::now() + sleepTime, std::forward<Pred>(pred)); } template <typename Pred> void wait(std::unique_lock<mutex>& lk, Pred&& pred) { while (!pred()) { wait(lk); } } void wait(std::unique_lock<mutex>& lk) { ffrt_cond_wait(this, lk.mutex()); } void notify_one() noexcept { ffrt_cond_signal(this); } void notify_all() noexcept { ffrt_cond_broadcast(this); } private: template <typename Rep, typename Period> cv_status _wait_for(std::unique_lock<mutex>& lk, const std::chrono::duration<Rep, Period>& dur) noexcept { timespec ts; std::chrono::nanoseconds ns = std::chrono::steady_clock::now().time_since_epoch(); ns += std::chrono::duration_cast<std::chrono::nanoseconds>(dur); ts.tv_sec = std::chrono::duration_cast<std::chrono::seconds>(ns).count(); ns -= std::chrono::seconds(ts.tv_sec); ts.tv_nsec = static_cast<long>(ns.count()); auto ret = ffrt_cond_timedwait(this, lk.mutex(), &ts); if (ret == ffrt_success) { return cv_status::no_timeout; } return cv_status::timeout; } }; } // namespace ffrt #endif