9
9
#ifndef CGRAPH_UTHREADPRIMARY_H
10
10
#define CGRAPH_UTHREADPRIMARY_H
11
11
12
+ #include < vector>
13
+ #include < mutex>
14
+
12
15
#include " UThreadBase.h"
13
16
14
17
CGRAPH_NAMESPACE_BEGIN
@@ -17,7 +20,6 @@ class UThreadPrimary : public UThreadBase {
17
20
protected:
18
21
explicit UThreadPrimary () {
19
22
index_ = CGRAPH_SECONDARY_THREAD_COMMON_ID;
20
- steal_range_ = 0 ;
21
23
pool_threads_ = nullptr ;
22
24
type_ = CGRAPH_THREAD_TYPE_PRIMARY;
23
25
}
@@ -29,7 +31,7 @@ class UThreadPrimary : public UThreadBase {
29
31
CGRAPH_ASSERT_NOT_NULL (config_)
30
32
31
33
is_init_ = true ;
32
- steal_range_ = config_-> calcStealRange ();
34
+ buildStealTargets ();
33
35
thread_ = std::move (std::thread (&UThreadPrimary::run, this ));
34
36
setSchedParam ();
35
37
setAffinity (index_);
@@ -64,7 +66,7 @@ class UThreadPrimary : public UThreadBase {
64
66
* 线程执行函数
65
67
* @return
66
68
*/
67
- CStatus run () override {
69
+ CStatus run () final {
68
70
CGRAPH_FUNCTION_BEGIN
69
71
CGRAPH_ASSERT_INIT (true )
70
72
CGRAPH_ASSERT_NOT_NULL (pool_threads_)
@@ -91,7 +93,7 @@ class UThreadPrimary : public UThreadBase {
91
93
if (popTask (task) || popPoolTask (task) || stealTask (task)) {
92
94
runTask (task);
93
95
} else {
94
- std::this_thread::yield ();
96
+ fatWait ();
95
97
}
96
98
}
97
99
@@ -102,7 +104,22 @@ class UThreadPrimary : public UThreadBase {
102
104
// 尝试从主线程中获取/盗取批量task,如果成功,则依次执行
103
105
runTasks (tasks);
104
106
} else {
105
- std::this_thread::yield ();
107
+ fatWait ();
108
+ }
109
+ }
110
+
111
+
112
+ /* *
113
+ * 如果总是进入无task的状态,则开始休眠
114
+ * 休眠一定时间后,然后恢复执行状态,避免出现
115
+ */
116
+ CVoid fatWait () {
117
+ cur_empty_epoch_++;
118
+ std::this_thread::yield ();
119
+ if (cur_empty_epoch_ >= config_->primary_thread_busy_epoch_ ) {
120
+ CGRAPH_UNIQUE_LOCK lk (mutex_);
121
+ cv_.wait_for (lk, std::chrono::milliseconds (config_->primary_thread_empty_interval_ ));
122
+ cur_empty_epoch_ = 0 ;
106
123
}
107
124
}
108
125
@@ -117,6 +134,7 @@ class UThreadPrimary : public UThreadBase {
117
134
|| secondary_queue_.tryPush (std::move (task)))) {
118
135
std::this_thread::yield ();
119
136
}
137
+ cv_.notify_one ();
120
138
}
121
139
122
140
@@ -164,16 +182,15 @@ class UThreadPrimary : public UThreadBase {
164
182
* 窃取的时候,仅从相邻的primary线程中窃取
165
183
* 待窃取相邻的数量,不能超过默认primary线程数
166
184
*/
167
- for (int i = 0 ; i < steal_range_; i++ ) {
185
+ for (auto & target : steal_targets_ ) {
168
186
/* *
169
187
* 从线程中周围的thread中,窃取任务。
170
188
* 如果成功,则返回true,并且执行任务。
171
189
* steal 的时候,先从第二个队列里偷,从而降低触碰锁的概率
172
190
*/
173
- int curIndex = (index_ + i + 1 ) % config_->default_thread_size_ ;
174
- if (likely ((*pool_threads_)[curIndex])
175
- && (((*pool_threads_)[curIndex])->secondary_queue_ .trySteal (task))
176
- || ((*pool_threads_)[curIndex])->primary_queue_ .trySteal (task)) {
191
+ if (likely ((*pool_threads_)[target])
192
+ && (((*pool_threads_)[target])->secondary_queue_ .trySteal (task))
193
+ || ((*pool_threads_)[target])->primary_queue_ .trySteal (task)) {
177
194
return true ;
178
195
}
179
196
}
@@ -192,13 +209,12 @@ class UThreadPrimary : public UThreadBase {
192
209
return false ;
193
210
}
194
211
195
- for (int i = 0 ; i < steal_range_; i++) {
196
- int curIndex = (index_ + i + 1 ) % config_->default_thread_size_ ;
197
- if (likely ((*pool_threads_)[curIndex])) {
198
- bool result = ((*pool_threads_)[curIndex])->secondary_queue_ .trySteal (tasks, config_->max_steal_batch_size_ );
212
+ for (auto & target : steal_targets_) {
213
+ if (likely ((*pool_threads_)[target])) {
214
+ bool result = ((*pool_threads_)[target])->secondary_queue_ .trySteal (tasks, config_->max_steal_batch_size_ );
199
215
auto leftSize = config_->max_steal_batch_size_ - tasks.size ();
200
216
if (leftSize > 0 ) {
201
- result |= ((*pool_threads_)[curIndex ])->primary_queue_ .trySteal (tasks, leftSize);
217
+ result |= ((*pool_threads_)[target ])->primary_queue_ .trySteal (tasks, leftSize);
202
218
}
203
219
204
220
if (result) {
@@ -216,12 +232,30 @@ class UThreadPrimary : public UThreadBase {
216
232
return false ;
217
233
}
218
234
235
+
236
+ /* *
237
+ * 构造 steal 范围的 target,避免每次盗取的时候,重复计算
238
+ * @return
239
+ */
240
+ CVoid buildStealTargets () {
241
+ steal_targets_.clear ();
242
+ for (int i = 0 ; i < config_->calcStealRange (); i++) {
243
+ auto target = (index_ + i + 1 ) % config_->default_thread_size_ ;
244
+ steal_targets_.push_back (target);
245
+ }
246
+ steal_targets_.shrink_to_fit ();
247
+ }
248
+
219
249
private:
220
250
int index_; // 线程index
221
- int steal_range_; // 偷窃的范围信息
222
- UWorkStealingQueue primary_queue_; // 内部队列信息
223
- UWorkStealingQueue secondary_queue_; // 第二个队列,用于减少触锁概率,提升性能
251
+ int cur_empty_epoch_ = 0 ; // 当前空转的轮数信息
252
+ UWorkStealingQueue<UTask> primary_queue_; // 内部队列信息
253
+ UWorkStealingQueue<UTask> secondary_queue_; // 第二个队列,用于减少触锁概率,提升性能
224
254
std::vector<UThreadPrimary *>* pool_threads_; // 用于存放线程池中的线程信息
255
+ std::vector<int > steal_targets_; // 被偷的目标信息
256
+
257
+ std::mutex mutex_;
258
+ std::condition_variable cv_;
225
259
226
260
friend class UThreadPool ;
227
261
friend class UAllocator ;
0 commit comments