aboutsummaryrefslogtreecommitdiff
path: root/works/life/operating-system-experiment/Thread.h
blob: c71c11ff0cbcabf39340d8af8f2ffa26148ae956 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#ifndef HEADER_THREAD_H
#define HEADER_THREAD_H

#include "Base.h"

#ifdef __cplusplus

#include <functional>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>

namespace cru {
class CRU_API Thread {
public:
  Thread() = default;
  template <typename Fn, typename... Args> Thread(Fn &&process, Args &&...args);
  Thread(const Thread &other) = delete;
  Thread(Thread &&other) noexcept;
  Thread &operator=(const Thread &other) = delete;
  Thread &operator=(Thread &&other) noexcept;
  ~Thread();

public:
  void Join();
  void Detach();

  void swap(Thread &other) noexcept;

private:
  void Destroy() noexcept;

private:
  bool detached_ = false;
  bool joined_ = false;

#ifdef CRU_WINDOWS
  DWORD thread_id_ = 0;
  HANDLE thread_handle_ = nullptr;
#endif
};

namespace details {
#ifdef CRU_WINDOWS
CRU_API DWORD WINAPI ThreadProc(_In_ LPVOID lpParameter);
#else
#endif
} // namespace details

template <typename Fn, typename... Args>
Thread::Thread(Fn &&process, Args &&...args) {
  std::tuple<std::decay_t<Args>...> a{std::forward<Args>(args)...};
  auto p = new std::function<void()>(
      [process = std::forward<Fn>(process), args = std::move(a)]() {
        std::apply(process, std::move(args));
      });

#ifdef CRU_WINDOWS
  thread_handle_ = ::CreateThread(nullptr, 0, &::cru::details::ThreadProc,
                                  static_cast<void *>(p), 0, &thread_id_);
#endif
};
} // namespace cru

#endif

#endif