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_THREAD_H
16 #define FFRT_API_CPP_THREAD_H
17 #include <memory>
18 #include "cpp/task.h"
19 
20 namespace ffrt {
21 class thread {
22 public:
thread()23     thread() noexcept
24     {
25     }
26 
27     template <typename Fn, typename... Args,
28         class = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Fn>>, thread>>>
thread(const char * name,qos qos_,Fn && fn,Args &&...args)29     explicit thread(const char* name, qos qos_, Fn&& fn, Args&&... args)
30     {
31         is_joinable = std::make_unique<task_handle>();
32         using Target = std::tuple<std::decay_t<Fn>, std::decay_t<Args>...>;
33         auto tup = new Target(std::forward<Fn>(fn), std::forward<Args>(args)...);
34         *is_joinable = ffrt::submit_h([tup]() {
35             execute(*tup, std::make_index_sequence<std::tuple_size_v<Target>>());
36             delete tup;
37             }, {}, {}, ffrt::task_attr().name(name).qos(qos_));
38     }
39 
40     template <typename Fn, typename... Args,
41         class = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Fn>>, thread>>>
thread(qos qos_,Fn && fn,Args &&...args)42     explicit thread(qos qos_, Fn&& fn, Args&&... args)
43     {
44         is_joinable = std::make_unique<task_handle>();
45         using Target = std::tuple<std::decay_t<Fn>, std::decay_t<Args>...>;
46         auto tup = new Target(std::forward<Fn>(fn), std::forward<Args>(args)...);
47         *is_joinable = ffrt::submit_h([tup]() {
48             execute(*tup, std::make_index_sequence<std::tuple_size_v<Target>>());
49             delete tup;
50             }, {}, {}, ffrt::task_attr().qos(qos_));
51     }
52 
53     template <class Fn, class... Args,
54         class = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Fn>>, thread>>,
55         class = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Fn>>, char*>>,
56         class = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Fn>>, qos>>>
57     explicit thread(Fn&& fn, Args&& ... args)
58     {
59         is_joinable = std::make_unique<task_handle>();
60         using Target = std::tuple<std::decay_t<Fn>, std::decay_t<Args>...>;
61         auto tup = new Target (std::forward<Fn>(fn), std::forward<Args>(args)...);
62         *is_joinable = ffrt::submit_h([tup]() {
63             execute(*tup, std::make_index_sequence<std::tuple_size_v<Target>>());
64             delete tup;
65             });
66     }
67 
68     thread(const thread&) = delete;
69     thread& operator=(const thread&) = delete;
70 
thread(thread && th)71     thread(thread&& th) noexcept
72     {
73         swap(th);
74     }
75 
76     thread& operator=(thread&& th) noexcept
77     {
78         if (this != &th) {
79             thread tmp(std::move(th));
80             swap(tmp);
81         }
82         return *this;
83     }
84 
joinable()85     bool joinable() const noexcept
86     {
87         return is_joinable.get() && *is_joinable;
88     }
89 
detach()90     void detach() noexcept
91     {
92         is_joinable = nullptr;
93     }
94 
join()95     void join() noexcept
96     {
97         if (joinable()) {
98             ffrt::wait({*is_joinable});
99             is_joinable = nullptr;
100         }
101     }
102 
~thread()103     ~thread()
104     {
105         if (joinable()) {
106             std::terminate();
107         }
108     }
109 
110 private:
111     template<class Target, size_t... Idxs>
execute(Target & tup,std::index_sequence<Idxs...>)112     static inline void execute(Target& tup,
113         std::index_sequence<Idxs...>)
114     {
115         std::invoke(std::move(std::get<Idxs>(tup))...);
116     }
117 
swap(thread & other)118     void swap(thread& other) noexcept
119     {
120         is_joinable.swap(other.is_joinable);
121     };
122     std::unique_ptr<task_handle> is_joinable;
123 };
124 } // namespace ffrt
125 #endif
126