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