-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy paththread.h
158 lines (127 loc) · 4.1 KB
/
thread.h
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// todo:尽可能地更换设施,这不是jSTL的一部分
#include <process.h>
#include <windows.h>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <utility>
#include "functional/invoke.h"
#include "type_traits/decay.h"
#include "type_traits/enable_if.h"
#include "type_traits/remove_cvref.h"
#include "type_traits/is_same.h"
#include "utility/exchange.h"
#include "utility/forward.h"
#include "utility/move.h"
namespace my {
using thread_id_t = unsigned int;
namespace this_thread {
inline thread_id_t get_id() noexcept {
return GetCurrentThreadId();
}
} // namespace this_thread
class thread {
struct thread_t {
void* _handle; // 线程句柄
thread_id_t _id; // 线程id
};
thread_t _thr;
public:
// 默认构造
thread() noexcept : _thr{} {}
// 移动构造
thread(thread&& _other) noexcept : _thr(exchange(_other._thr, {})) {}
thread& operator=(thread&& t) noexcept {
if (joinable()) {
terminate();
}
swap(t);
return *this;
}
// 禁用拷贝构造
thread(const thread&) = delete;
thread& operator=(const thread&) = delete;
// 有参构造
template <
class Fn, class... Args,
enable_if_t<!is_same_v<remove_cvref_t<Fn>, my::thread>,
int> = 0> // Fn不能是thread类型
explicit thread(Fn&& fn, Args&&... args) {
_start(forward<Fn>(fn),
forward<Args>(args)...); // 完美转发到_start函数完成真正的工作
}
// 析构函数
~thread() {
if (joinable()) {
terminate();
}
}
void swap(thread& t) noexcept {
std::swap(_thr, t._thr);
}
bool joinable() const noexcept {
return !(_thr._handle == nullptr);
}
void join() {
if (!joinable()) {
throw std::runtime_error("Thread is not joinable");
}
WaitForSingleObject(_thr._handle, INFINITE);
CloseHandle(_thr._handle);
_thr = {};
}
void detach() {
if (!joinable()) {
throw std::runtime_error("Thread is not joinable");
}
CloseHandle(_thr._handle);
_thr = {};
}
thread_id_t get_id() const noexcept;
friend bool operator==(const thread& left, const thread& right) noexcept;
template <class Ch, class Tr>
friend auto operator<<(std::basic_ostream<Ch, Tr>& stream,
const thread& th);
private:
template <class _tuple, size_t... _indices>
static unsigned int _invoke(void* _rawVals) noexcept {
const std::unique_ptr<_tuple> _fnVals{static_cast<_tuple*>(_rawVals)};
_tuple& _tup = *_fnVals.get();
invoke(move(std::get<_indices>(_tup))...);
return 0;
}
template <class _tuple, size_t... _indices>
static constexpr auto _get_invoke(
std::index_sequence<_indices...>) noexcept {
return &_invoke<_tuple, _indices...>;
}
template <class Fn, class... Args>
void _start(Fn&& fn, Args&&... args) {
using _tuple = std::tuple<decay_t<Fn>, decay_t<Args>...>;
std::unique_ptr<_tuple> _decay_copied =
std::make_unique<_tuple>(forward<Fn>(fn), forward<Args>(args)...);
constexpr auto _invoker_proc = this->_get_invoke<_tuple>(
std::make_index_sequence<1 + sizeof...(Args)>{});
_thr._handle = reinterpret_cast<void*>(_beginthreadex(
nullptr, 0, _invoker_proc, _decay_copied.get(), 0, &_thr._id));
if (_thr._handle) {
(void)_decay_copied.release();
} else {
_thr._id = 0;
std::cerr << "Error creating thread: " << _thr._handle << std::endl;
throw std::runtime_error("Error creating thread");
}
}
};
inline thread_id_t thread::get_id() const noexcept {
return _thr._id;
}
inline bool operator==(const thread& left, const thread& right) noexcept {
return left._thr._id == right._thr._id;
}
template <class Ch, class Tr>
inline auto operator<<(std::basic_ostream<Ch, Tr>& stream, const thread& t) {
stream << t._thr._id;
return stream;
}
} // namespace my