hikyuu 2.6.2__py3-none-win_amd64.whl → 2.6.3__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hikyuu/__init__.py +1 -1
- hikyuu/__init__.pyi +25 -9
- hikyuu/analysis/__init__.pyi +16 -0
- hikyuu/analysis/analysis.pyi +17 -1
- hikyuu/core.pyi +18 -2
- hikyuu/cpp/core310.pyd +0 -0
- hikyuu/cpp/core310.pyi +369 -41
- hikyuu/cpp/core311.pyd +0 -0
- hikyuu/cpp/core311.pyi +369 -41
- hikyuu/cpp/core312.pyd +0 -0
- hikyuu/cpp/core312.pyi +369 -41
- hikyuu/cpp/core313.pyd +0 -0
- hikyuu/cpp/core313.pyi +369 -41
- hikyuu/cpp/core39.pyd +0 -0
- hikyuu/cpp/core39.pyi +369 -41
- hikyuu/cpp/hikyuu.dll +0 -0
- hikyuu/cpp/hikyuu.lib +0 -0
- hikyuu/cpp/sqlite3.dll +0 -0
- hikyuu/draw/drawplot/bokeh_draw.pyi +21 -5
- hikyuu/draw/drawplot/echarts_draw.pyi +21 -5
- hikyuu/draw/drawplot/matplotlib_draw.py +22 -0
- hikyuu/draw/drawplot/matplotlib_draw.pyi +21 -5
- hikyuu/draw/kaufman.py +2 -2
- hikyuu/draw/kaufman.pyi +2 -2
- hikyuu/extend.pyi +21 -5
- hikyuu/hub.pyi +6 -6
- hikyuu/include/hikyuu/Block.h +20 -0
- hikyuu/include/hikyuu/KQuery.h +8 -0
- hikyuu/include/hikyuu/Stock.h +1 -1
- hikyuu/include/hikyuu/StockManager.h +6 -0
- hikyuu/include/hikyuu/indicator/Indicator.h +5 -0
- hikyuu/include/hikyuu/indicator/IndicatorImp.h +8 -3
- hikyuu/include/hikyuu/indicator/crt/INSUM.h +5 -10
- hikyuu/include/hikyuu/indicator/crt/RSI.h +2 -18
- hikyuu/include/hikyuu/plugin/backtest.h +3 -2
- hikyuu/include/hikyuu/plugin/extind.h +150 -0
- hikyuu/include/hikyuu/plugin/interface/BackTestPluginInterface.h +2 -1
- hikyuu/include/hikyuu/plugin/interface/ExtendIndicatorsPluginInterface.h +26 -0
- hikyuu/include/hikyuu/plugin/interface/plugins.h +2 -0
- hikyuu/include/hikyuu/strategy/BrokerTradeManager.h +7 -5
- hikyuu/include/hikyuu/strategy/Strategy.h +22 -9
- hikyuu/include/hikyuu/trade_manage/OrderBrokerBase.h +11 -4
- hikyuu/include/hikyuu/trade_manage/TradeManager.h +8 -5
- hikyuu/include/hikyuu/trade_manage/TradeManagerBase.h +6 -4
- hikyuu/include/hikyuu/trade_manage/TradeRecord.h +9 -1
- hikyuu/include/hikyuu/trade_sys/multifactor/MultiFactorBase.h +8 -5
- hikyuu/include/hikyuu/trade_sys/multifactor/crt/MF_EqualWeight.h +4 -1
- hikyuu/include/hikyuu/trade_sys/multifactor/crt/MF_ICIRWeight.h +4 -1
- hikyuu/include/hikyuu/trade_sys/multifactor/crt/MF_ICWeight.h +4 -1
- hikyuu/include/hikyuu/trade_sys/multifactor/crt/MF_Weight.h +4 -1
- hikyuu/include/hikyuu/trade_sys/multifactor/imp/EqualWeightMultiFactor.h +2 -1
- hikyuu/include/hikyuu/trade_sys/multifactor/imp/ICIRMultiFactor.h +2 -1
- hikyuu/include/hikyuu/trade_sys/multifactor/imp/ICMultiFactor.h +2 -1
- hikyuu/include/hikyuu/trade_sys/multifactor/imp/WeightMultiFactor.h +1 -1
- hikyuu/include/hikyuu/trade_sys/system/TradeRequest.h +7 -4
- hikyuu/include/hikyuu/trade_sys/system/imp/WalkForwardTradeManager.h +17 -13
- hikyuu/include/hikyuu/utilities/thread/{MQStealThreadPool.h → GlobalMQStealThreadPool.h} +12 -12
- hikyuu/include/hikyuu/utilities/thread/GlobalMQThreadPool.h +271 -0
- hikyuu/include/hikyuu/utilities/thread/{StealThreadPool.h → GlobalStealThreadPool.h} +11 -10
- hikyuu/include/hikyuu/utilities/thread/GlobalThreadPool.h +224 -0
- hikyuu/include/hikyuu/utilities/thread/InterruptFlag.h +16 -0
- hikyuu/include/hikyuu/utilities/thread/MQThreadPool.h +27 -70
- hikyuu/include/hikyuu/utilities/thread/ThreadPool.h +18 -53
- hikyuu/include/hikyuu/utilities/thread/ThreadSafeQueue.h +4 -0
- hikyuu/include/hikyuu/utilities/thread/algorithm.h +9 -9
- hikyuu/include/hikyuu/utilities/thread/thread.h +4 -0
- hikyuu/include/hikyuu/version.h +4 -4
- hikyuu/plugin/backtest.dll +0 -0
- hikyuu/plugin/dataserver.dll +0 -0
- hikyuu/plugin/device.dll +0 -0
- hikyuu/plugin/extind.dll +0 -0
- hikyuu/plugin/import2hdf5.dll +0 -0
- hikyuu/trade_manage/__init__.pyi +21 -5
- hikyuu/trade_manage/broker.py +8 -8
- hikyuu/trade_manage/broker.pyi +4 -4
- hikyuu/trade_manage/broker_easytrader.py +3 -3
- hikyuu/trade_manage/broker_easytrader.pyi +2 -2
- hikyuu/trade_manage/broker_mail.py +2 -2
- hikyuu/trade_manage/broker_mail.pyi +2 -2
- hikyuu/trade_manage/trade.pyi +21 -5
- hikyuu/util/singleton.pyi +1 -1
- {hikyuu-2.6.2.dist-info → hikyuu-2.6.3.dist-info}/METADATA +1 -1
- {hikyuu-2.6.2.dist-info → hikyuu-2.6.3.dist-info}/RECORD +87 -82
- {hikyuu-2.6.2.dist-info → hikyuu-2.6.3.dist-info}/LICENSE +0 -0
- {hikyuu-2.6.2.dist-info → hikyuu-2.6.3.dist-info}/WHEEL +0 -0
- {hikyuu-2.6.2.dist-info → hikyuu-2.6.3.dist-info}/entry_points.txt +0 -0
- {hikyuu-2.6.2.dist-info → hikyuu-2.6.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* StealGlobalMQThreadPool.h
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2019 hikyuu.org
|
|
5
|
+
*
|
|
6
|
+
* Created on: 2019-9-16
|
|
7
|
+
* Author: fasiondog
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#pragma once
|
|
11
|
+
|
|
12
|
+
#include <future>
|
|
13
|
+
#include <thread>
|
|
14
|
+
#include <chrono>
|
|
15
|
+
#include <vector>
|
|
16
|
+
#include "InterruptFlag.h"
|
|
17
|
+
#include "FuncWrapper.h"
|
|
18
|
+
#include "ThreadSafeQueue.h"
|
|
19
|
+
#include "../cppdef.h"
|
|
20
|
+
|
|
21
|
+
#ifdef __GNUC__
|
|
22
|
+
#pragma GCC diagnostic push
|
|
23
|
+
#pragma GCC diagnostic ignored "-Wsign-compare"
|
|
24
|
+
#endif
|
|
25
|
+
|
|
26
|
+
#ifndef HKU_UTILS_API
|
|
27
|
+
#define HKU_UTILS_API
|
|
28
|
+
#endif
|
|
29
|
+
|
|
30
|
+
namespace hku {
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @brief 全局分布式线程池,只适合程序运行期内一直保持运行的情况
|
|
34
|
+
* @details
|
|
35
|
+
* @ingroup GlobalMQThreadPool
|
|
36
|
+
*/
|
|
37
|
+
#ifdef _MSC_VER
|
|
38
|
+
class GlobalMQThreadPool {
|
|
39
|
+
#else
|
|
40
|
+
class HKU_UTILS_API GlobalMQThreadPool {
|
|
41
|
+
#endif
|
|
42
|
+
public:
|
|
43
|
+
/**
|
|
44
|
+
* 默认构造函数,创建和当前系统CPU数一致的线程数
|
|
45
|
+
*/
|
|
46
|
+
GlobalMQThreadPool() : GlobalMQThreadPool(std::thread::hardware_concurrency()) {}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 构造函数,创建指定数量的线程
|
|
50
|
+
* @param n 指定的线程数
|
|
51
|
+
* @param until_empty 任务队列为空时,自动停止运行
|
|
52
|
+
*/
|
|
53
|
+
explicit GlobalMQThreadPool(size_t n, bool until_empty = true)
|
|
54
|
+
: m_done(false), m_worker_num(n), m_runnging_until_empty(until_empty) {
|
|
55
|
+
try {
|
|
56
|
+
m_interrupt_flags.resize(m_worker_num, nullptr);
|
|
57
|
+
for (int i = 0; i < m_worker_num; i++) {
|
|
58
|
+
// 创建工作线程及其任务队列
|
|
59
|
+
m_queues.push_back(
|
|
60
|
+
std::unique_ptr<ThreadSafeQueue<task_type>>(new ThreadSafeQueue<task_type>));
|
|
61
|
+
}
|
|
62
|
+
// 初始完毕所有线程资源后再启动线程
|
|
63
|
+
for (int i = 0; i < m_worker_num; i++) {
|
|
64
|
+
m_threads.push_back(std::thread(&GlobalMQThreadPool::worker_thread, this, i));
|
|
65
|
+
}
|
|
66
|
+
} catch (...) {
|
|
67
|
+
m_done = true;
|
|
68
|
+
throw;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 析构函数,等待并阻塞至线程池内所有任务完成
|
|
74
|
+
*/
|
|
75
|
+
~GlobalMQThreadPool() {
|
|
76
|
+
if (!m_done) {
|
|
77
|
+
stop();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** 获取工作线程数 */
|
|
82
|
+
size_t worker_num() const {
|
|
83
|
+
return m_worker_num;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** 剩余任务数 */
|
|
87
|
+
size_t remain_task_count() const {
|
|
88
|
+
size_t total = 0;
|
|
89
|
+
for (size_t i = 0; i < m_worker_num; i++) {
|
|
90
|
+
total += m_queues[i]->size();
|
|
91
|
+
}
|
|
92
|
+
return total;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** 先线程池提交任务后返回的对应 future 的类型 */
|
|
96
|
+
template <typename ResultType>
|
|
97
|
+
using task_handle = std::future<ResultType>;
|
|
98
|
+
|
|
99
|
+
#ifdef _MSC_VER
|
|
100
|
+
#pragma warning(push)
|
|
101
|
+
#pragma warning(disable : 4996)
|
|
102
|
+
#endif
|
|
103
|
+
|
|
104
|
+
/** 向线程池提交任务 */
|
|
105
|
+
template <typename FunctionType>
|
|
106
|
+
auto submit(FunctionType f) {
|
|
107
|
+
if (m_thread_need_stop.isSet() || m_done) {
|
|
108
|
+
throw std::logic_error("You can't submit a task to the stopped GlobalMQThreadPool!");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
typedef typename std::invoke_result<FunctionType>::type result_type;
|
|
112
|
+
std::packaged_task<result_type()> task(f);
|
|
113
|
+
task_handle<result_type> res(task.get_future());
|
|
114
|
+
|
|
115
|
+
// 向空队列或任务数最小的队列中加入任务
|
|
116
|
+
size_t min_count = std::numeric_limits<size_t>::max();
|
|
117
|
+
int index = 0;
|
|
118
|
+
for (int i = 0; i < m_worker_num; ++i) {
|
|
119
|
+
size_t cur_count = m_queues[i]->size();
|
|
120
|
+
if (cur_count == 0) {
|
|
121
|
+
index = i;
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (cur_count < min_count) {
|
|
126
|
+
min_count = cur_count;
|
|
127
|
+
index = i;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
m_queues[index]->push(std::move(task));
|
|
132
|
+
return res;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
#ifdef _MSC_VER
|
|
136
|
+
#pragma warning(pop)
|
|
137
|
+
#endif
|
|
138
|
+
|
|
139
|
+
/** 返回线程池结束状态 */
|
|
140
|
+
bool done() const {
|
|
141
|
+
return m_done;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* 等待各线程完成当前执行的任务后立即结束退出
|
|
146
|
+
*/
|
|
147
|
+
void stop() {
|
|
148
|
+
if (m_done) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
m_done = true;
|
|
153
|
+
|
|
154
|
+
// 同时加入结束任务指示,以便在dll退出时也能够终止
|
|
155
|
+
for (size_t i = 0; i < m_worker_num; i++) {
|
|
156
|
+
if (m_interrupt_flags[i]) {
|
|
157
|
+
m_interrupt_flags[i]->set();
|
|
158
|
+
}
|
|
159
|
+
m_queues[i]->push(FuncWrapper());
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
for (size_t i = 0; i < m_worker_num; i++) {
|
|
163
|
+
if (m_threads[i].joinable()) {
|
|
164
|
+
m_threads[i].join();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
for (size_t i = 0; i < m_worker_num; i++) {
|
|
169
|
+
m_queues[i]->clear();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* 等待并阻塞至线程池内所有任务完成
|
|
175
|
+
* @note 至此线程池能工作线程结束不可再使用
|
|
176
|
+
*/
|
|
177
|
+
void join() {
|
|
178
|
+
if (m_done) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// 指示各工作线程在未获取到工作任务时,停止运行
|
|
183
|
+
if (m_runnging_until_empty) {
|
|
184
|
+
while (true) {
|
|
185
|
+
bool can_quit = true;
|
|
186
|
+
for (size_t i = 0; i < m_worker_num; i++) {
|
|
187
|
+
if (m_queues[i]->size() != 0) {
|
|
188
|
+
can_quit = false;
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (can_quit) {
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
std::this_thread::yield();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
m_done = true;
|
|
201
|
+
for (size_t i = 0; i < m_worker_num; i++) {
|
|
202
|
+
if (m_interrupt_flags[i]) {
|
|
203
|
+
m_interrupt_flags[i]->set();
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
for (size_t i = 0; i < m_worker_num; i++) {
|
|
209
|
+
m_queues[i]->push(FuncWrapper());
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// 等待线程结束
|
|
213
|
+
for (size_t i = 0; i < m_worker_num; i++) {
|
|
214
|
+
if (m_threads[i].joinable()) {
|
|
215
|
+
m_threads[i].join();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
for (size_t i = 0; i < m_worker_num; i++) {
|
|
220
|
+
m_queues[i]->clear();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
m_done = true;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
private:
|
|
227
|
+
typedef FuncWrapper task_type;
|
|
228
|
+
std::atomic_bool m_done; // 线程池全局需终止指示
|
|
229
|
+
size_t m_worker_num; // 工作线程数量
|
|
230
|
+
bool m_runnging_until_empty; // 运行直到队列空时停止
|
|
231
|
+
|
|
232
|
+
std::vector<std::unique_ptr<ThreadSafeQueue<task_type>>> m_queues; // 线程任务队列
|
|
233
|
+
std::vector<InterruptFlag*> m_interrupt_flags; // 线程终止标志
|
|
234
|
+
std::vector<std::thread> m_threads; // 工作线程
|
|
235
|
+
|
|
236
|
+
// 线程本地变量
|
|
237
|
+
#if CPP_STANDARD >= CPP_STANDARD_17 && !defined(__clang__)
|
|
238
|
+
inline static thread_local ThreadSafeQueue<task_type>* m_local_work_queue =
|
|
239
|
+
nullptr; // 本地任务队列
|
|
240
|
+
inline static thread_local InterruptFlag m_thread_need_stop; // 线程停止运行指示
|
|
241
|
+
#else
|
|
242
|
+
static thread_local ThreadSafeQueue<task_type>* m_local_work_queue; // 本地任务队列
|
|
243
|
+
static thread_local InterruptFlag m_thread_need_stop; // 线程停止运行指示
|
|
244
|
+
#endif
|
|
245
|
+
|
|
246
|
+
void worker_thread(int index) {
|
|
247
|
+
m_interrupt_flags[index] = &m_thread_need_stop;
|
|
248
|
+
m_local_work_queue = m_queues[index].get();
|
|
249
|
+
while (!m_thread_need_stop.isSet() || !m_done) {
|
|
250
|
+
run_pending_task();
|
|
251
|
+
}
|
|
252
|
+
m_local_work_queue = nullptr;
|
|
253
|
+
m_interrupt_flags[index] = nullptr;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
static void run_pending_task() {
|
|
257
|
+
task_type task;
|
|
258
|
+
m_local_work_queue->wait_and_pop(task);
|
|
259
|
+
if (task.isNullTask()) {
|
|
260
|
+
m_thread_need_stop.set();
|
|
261
|
+
} else {
|
|
262
|
+
task();
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
} /* namespace hku */
|
|
268
|
+
|
|
269
|
+
#ifdef __GNUC__
|
|
270
|
+
#pragma GCC diagnostic pop
|
|
271
|
+
#endif
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
*
|
|
2
|
+
* GlobalStealThreadPool.h
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) 2019 hikyuu.org
|
|
5
5
|
*
|
|
@@ -37,22 +37,22 @@ namespace hku {
|
|
|
37
37
|
* @ingroup ThreadPool
|
|
38
38
|
*/
|
|
39
39
|
#ifdef _MSC_VER
|
|
40
|
-
class
|
|
40
|
+
class GlobalStealThreadPool {
|
|
41
41
|
#else
|
|
42
|
-
class HKU_UTILS_API
|
|
42
|
+
class HKU_UTILS_API GlobalStealThreadPool {
|
|
43
43
|
#endif
|
|
44
44
|
public:
|
|
45
45
|
/**
|
|
46
46
|
* 默认构造函数,创建和当前系统CPU数一致的线程数
|
|
47
47
|
*/
|
|
48
|
-
|
|
48
|
+
GlobalStealThreadPool() : GlobalStealThreadPool(std::thread::hardware_concurrency()) {}
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* 构造函数,创建指定数量的线程
|
|
52
52
|
* @param n 指定的线程数
|
|
53
53
|
* @param until_empty 任务队列为空时,自动停止运行
|
|
54
54
|
*/
|
|
55
|
-
explicit
|
|
55
|
+
explicit GlobalStealThreadPool(size_t n, bool until_empty = true)
|
|
56
56
|
: m_done(false), m_worker_num(n), m_running_until_empty(until_empty) {
|
|
57
57
|
try {
|
|
58
58
|
m_interrupt_flags.resize(m_worker_num, nullptr);
|
|
@@ -62,7 +62,7 @@ public:
|
|
|
62
62
|
}
|
|
63
63
|
// 初始完毕所有线程资源后再启动线程
|
|
64
64
|
for (int i = 0; i < m_worker_num; i++) {
|
|
65
|
-
m_threads.emplace_back(&
|
|
65
|
+
m_threads.emplace_back(&GlobalStealThreadPool::worker_thread, this, i);
|
|
66
66
|
}
|
|
67
67
|
} catch (...) {
|
|
68
68
|
m_done = true;
|
|
@@ -73,7 +73,7 @@ public:
|
|
|
73
73
|
/**
|
|
74
74
|
* 析构函数,等待并阻塞至线程池内所有任务完成
|
|
75
75
|
*/
|
|
76
|
-
~
|
|
76
|
+
~GlobalStealThreadPool() {
|
|
77
77
|
if (!m_done) {
|
|
78
78
|
join();
|
|
79
79
|
}
|
|
@@ -109,7 +109,8 @@ public:
|
|
|
109
109
|
template <typename FunctionType>
|
|
110
110
|
auto submit(FunctionType f) {
|
|
111
111
|
if (m_thread_need_stop.isSet() || m_done) {
|
|
112
|
-
throw std::logic_error(
|
|
112
|
+
throw std::logic_error(
|
|
113
|
+
"You can't submit a task to the stopped GlobalStealThreadPool!!");
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
typedef typename std::invoke_result<FunctionType>::type result_type;
|
|
@@ -252,12 +253,12 @@ private:
|
|
|
252
253
|
void worker_thread(int index) {
|
|
253
254
|
m_interrupt_flags[index] = &m_thread_need_stop;
|
|
254
255
|
m_index = index;
|
|
255
|
-
m_local_work_queue = m_queues[
|
|
256
|
+
m_local_work_queue = m_queues[index].get();
|
|
256
257
|
while (!m_thread_need_stop.isSet() && !m_done) {
|
|
257
258
|
run_pending_task();
|
|
258
259
|
}
|
|
259
260
|
m_local_work_queue = nullptr;
|
|
260
|
-
m_interrupt_flags[
|
|
261
|
+
m_interrupt_flags[index] = nullptr;
|
|
261
262
|
}
|
|
262
263
|
|
|
263
264
|
void run_pending_task() {
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* StealGlobalThreadPool.h
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2019 hikyuu.org
|
|
5
|
+
*
|
|
6
|
+
* Created on: 2019-9-16
|
|
7
|
+
* Author: fasiondog
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#pragma once
|
|
11
|
+
#ifndef HIKYUU_UTILITIES_THREAD_THREADPOOL_H
|
|
12
|
+
#define HIKYUU_UTILITIES_THREAD_THREADPOOL_H
|
|
13
|
+
|
|
14
|
+
#include <cstdio>
|
|
15
|
+
#include <future>
|
|
16
|
+
#include <thread>
|
|
17
|
+
#include <vector>
|
|
18
|
+
#include "FuncWrapper.h"
|
|
19
|
+
#include "ThreadSafeQueue.h"
|
|
20
|
+
#include "InterruptFlag.h"
|
|
21
|
+
#include "../cppdef.h"
|
|
22
|
+
|
|
23
|
+
#ifdef __GNUC__
|
|
24
|
+
#pragma GCC diagnostic push
|
|
25
|
+
#pragma GCC diagnostic ignored "-Wsign-compare"
|
|
26
|
+
#endif
|
|
27
|
+
|
|
28
|
+
#ifndef HKU_UTILS_API
|
|
29
|
+
#define HKU_UTILS_API
|
|
30
|
+
#endif
|
|
31
|
+
|
|
32
|
+
namespace hku {
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @brief 全局集中式任务队列线程池,任务之间彼此独立不能互相等待
|
|
36
|
+
* @note 任务运行之间如存在先后顺序,只适合程序运行期内一直保持运行的情况
|
|
37
|
+
* @details
|
|
38
|
+
* @ingroup GlobalThreadPool
|
|
39
|
+
*/
|
|
40
|
+
#ifdef _MSC_VER
|
|
41
|
+
class GlobalThreadPool {
|
|
42
|
+
#else
|
|
43
|
+
class HKU_UTILS_API GlobalThreadPool {
|
|
44
|
+
#endif
|
|
45
|
+
public:
|
|
46
|
+
/**
|
|
47
|
+
* 默认构造函数,创建和当前系统CPU数一致的线程数
|
|
48
|
+
*/
|
|
49
|
+
GlobalThreadPool() : GlobalThreadPool(std::thread::hardware_concurrency()) {}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 构造函数,创建指定数量的线程
|
|
53
|
+
* @param n 指定的线程数
|
|
54
|
+
* @param until_empty join时,等待任务队列为空后停止运行
|
|
55
|
+
*/
|
|
56
|
+
explicit GlobalThreadPool(size_t n, bool until_empty = true)
|
|
57
|
+
: m_done(false), m_worker_num(n), m_running_until_empty(until_empty) {
|
|
58
|
+
try {
|
|
59
|
+
m_interrupt_flags.resize(m_worker_num, nullptr);
|
|
60
|
+
// 初始完毕所有线程资源后再启动线程
|
|
61
|
+
for (int i = 0; i < m_worker_num; i++) {
|
|
62
|
+
// 创建工作线程及其任务队列
|
|
63
|
+
m_threads.emplace_back(&GlobalThreadPool::worker_thread, this, i);
|
|
64
|
+
}
|
|
65
|
+
} catch (...) {
|
|
66
|
+
m_done = true;
|
|
67
|
+
throw;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* 析构函数,等待并阻塞至线程池内所有任务完成
|
|
73
|
+
*/
|
|
74
|
+
~GlobalThreadPool() {
|
|
75
|
+
if (!m_done) {
|
|
76
|
+
stop();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** 获取工作线程数 */
|
|
81
|
+
size_t worker_num() const {
|
|
82
|
+
return m_worker_num;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** 先线程池提交任务后返回的对应 future 的类型 */
|
|
86
|
+
template <typename ResultType>
|
|
87
|
+
using task_handle = std::future<ResultType>;
|
|
88
|
+
|
|
89
|
+
#ifdef _MSC_VER
|
|
90
|
+
#pragma warning(push)
|
|
91
|
+
#pragma warning(disable : 4996)
|
|
92
|
+
#endif
|
|
93
|
+
|
|
94
|
+
/** 向线程池提交任务 */
|
|
95
|
+
template <typename FunctionType>
|
|
96
|
+
auto submit(FunctionType f) {
|
|
97
|
+
if (m_thread_need_stop.isSet() || m_done) {
|
|
98
|
+
throw std::logic_error("You can't submit a task to the stopped task group!");
|
|
99
|
+
}
|
|
100
|
+
typedef typename std::invoke_result<FunctionType>::type result_type;
|
|
101
|
+
std::packaged_task<result_type()> task(f);
|
|
102
|
+
task_handle<result_type> res(task.get_future());
|
|
103
|
+
m_master_work_queue.push(std::move(task));
|
|
104
|
+
return res;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
#ifdef _MSC_VER
|
|
108
|
+
#pragma warning(pop)
|
|
109
|
+
#endif
|
|
110
|
+
|
|
111
|
+
/** 返回线程池结束状态 */
|
|
112
|
+
bool done() const {
|
|
113
|
+
return m_done;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** 剩余任务数 */
|
|
117
|
+
size_t remain_task_count() const {
|
|
118
|
+
return m_master_work_queue.size();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 等待各线程完成当前执行的任务后立即结束退出
|
|
123
|
+
*/
|
|
124
|
+
void stop() {
|
|
125
|
+
if (m_done) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
m_done = true;
|
|
130
|
+
|
|
131
|
+
// 同时加入结束任务指示,以便在dll退出时也能够终止
|
|
132
|
+
for (size_t i = 0; i < m_worker_num; i++) {
|
|
133
|
+
if (m_interrupt_flags[i]) {
|
|
134
|
+
m_interrupt_flags[i]->set();
|
|
135
|
+
}
|
|
136
|
+
m_master_work_queue.push(FuncWrapper());
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
for (size_t i = 0; i < m_worker_num; i++) {
|
|
140
|
+
if (m_threads[i].joinable()) {
|
|
141
|
+
m_threads[i].join();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
m_master_work_queue.clear();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
void join() {
|
|
149
|
+
if (m_done) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// 指示各工作线程在未获取到工作任务时,停止运行
|
|
154
|
+
if (m_running_until_empty) {
|
|
155
|
+
while (m_master_work_queue.size() > 0) {
|
|
156
|
+
std::this_thread::yield();
|
|
157
|
+
}
|
|
158
|
+
m_done = true;
|
|
159
|
+
for (size_t i = 0; i < m_worker_num; i++) {
|
|
160
|
+
if (m_interrupt_flags[i]) {
|
|
161
|
+
m_interrupt_flags[i]->set();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
for (size_t i = 0; i < m_worker_num; i++) {
|
|
167
|
+
m_master_work_queue.push(FuncWrapper());
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// 等待线程结束
|
|
171
|
+
for (size_t i = 0; i < m_worker_num; i++) {
|
|
172
|
+
if (m_threads[i].joinable()) {
|
|
173
|
+
m_threads[i].join();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
m_master_work_queue.clear();
|
|
178
|
+
m_done = true;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
private:
|
|
182
|
+
typedef FuncWrapper task_type;
|
|
183
|
+
std::atomic_bool m_done; // 线程池全局需终止指示
|
|
184
|
+
size_t m_worker_num; // 工作线程数量
|
|
185
|
+
bool m_running_until_empty; // 任务队列为空时,自动停止运行
|
|
186
|
+
|
|
187
|
+
ThreadSafeQueue<task_type> m_master_work_queue; // 主线程任务队列
|
|
188
|
+
std::vector<std::thread> m_threads; // 工作线程
|
|
189
|
+
std::vector<InterruptFlag*> m_interrupt_flags; // 线程中断标志
|
|
190
|
+
|
|
191
|
+
// 线程本地变量
|
|
192
|
+
#if CPP_STANDARD >= CPP_STANDARD_17 && !defined(__clang__)
|
|
193
|
+
inline static thread_local InterruptFlag m_thread_need_stop; // 线程停止运行指示
|
|
194
|
+
#else
|
|
195
|
+
static thread_local InterruptFlag m_thread_need_stop; // 线程停止运行指示
|
|
196
|
+
#endif
|
|
197
|
+
|
|
198
|
+
void worker_thread(int index) {
|
|
199
|
+
m_interrupt_flags[index] = &m_thread_need_stop;
|
|
200
|
+
while (!m_thread_need_stop.isSet() && !m_done) {
|
|
201
|
+
run_pending_task();
|
|
202
|
+
// std::this_thread::yield();
|
|
203
|
+
}
|
|
204
|
+
m_interrupt_flags[index] = nullptr;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
void run_pending_task() {
|
|
208
|
+
task_type task;
|
|
209
|
+
m_master_work_queue.wait_and_pop(task);
|
|
210
|
+
if (task.isNullTask()) {
|
|
211
|
+
m_thread_need_stop.set();
|
|
212
|
+
} else {
|
|
213
|
+
task();
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}; // namespace hku
|
|
217
|
+
|
|
218
|
+
} /* namespace hku */
|
|
219
|
+
|
|
220
|
+
#ifdef __GNUC__
|
|
221
|
+
#pragma GCC diagnostic pop
|
|
222
|
+
#endif
|
|
223
|
+
|
|
224
|
+
#endif /* HIKYUU_UTILITIES_THREAD_THREADPOOL_H */
|
|
@@ -15,6 +15,22 @@ class InterruptFlag {
|
|
|
15
15
|
public:
|
|
16
16
|
InterruptFlag() : m_flag(false) {}
|
|
17
17
|
|
|
18
|
+
explicit InterruptFlag(bool initial) : m_flag(initial) {}
|
|
19
|
+
|
|
20
|
+
InterruptFlag(const InterruptFlag& other)
|
|
21
|
+
: m_flag(other.m_flag.load(std::memory_order_relaxed)) {}
|
|
22
|
+
|
|
23
|
+
// 赋值运算符
|
|
24
|
+
InterruptFlag& operator=(const InterruptFlag& other) {
|
|
25
|
+
m_flag.store(other.m_flag.load(std::memory_order_relaxed), std::memory_order_relaxed);
|
|
26
|
+
return *this;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 转换为 bool 类型
|
|
30
|
+
operator bool() const {
|
|
31
|
+
return m_flag.load(std::memory_order_relaxed);
|
|
32
|
+
}
|
|
33
|
+
|
|
18
34
|
void set() {
|
|
19
35
|
m_flag = true;
|
|
20
36
|
}
|