|
|
@ -9,6 +9,9 @@ |
|
|
|
#ifndef CGRAPH_UTHREADPRIMARY_H |
|
|
|
#define CGRAPH_UTHREADPRIMARY_H |
|
|
|
|
|
|
|
#include <vector> |
|
|
|
#include <mutex> |
|
|
|
|
|
|
|
#include "UThreadBase.h" |
|
|
|
|
|
|
|
CGRAPH_NAMESPACE_BEGIN |
|
|
@ -17,7 +20,6 @@ class UThreadPrimary : public UThreadBase { |
|
|
|
protected: |
|
|
|
explicit UThreadPrimary() { |
|
|
|
index_ = CGRAPH_SECONDARY_THREAD_COMMON_ID; |
|
|
|
steal_range_ = 0; |
|
|
|
pool_threads_ = nullptr; |
|
|
|
type_ = CGRAPH_THREAD_TYPE_PRIMARY; |
|
|
|
} |
|
|
@ -29,7 +31,7 @@ protected: |
|
|
|
CGRAPH_ASSERT_NOT_NULL(config_) |
|
|
|
|
|
|
|
is_init_ = true; |
|
|
|
steal_range_ = config_->calcStealRange(); |
|
|
|
buildStealTargets(); |
|
|
|
thread_ = std::move(std::thread(&UThreadPrimary::run, this)); |
|
|
|
setSchedParam(); |
|
|
|
setAffinity(index_); |
|
|
@ -64,7 +66,7 @@ protected: |
|
|
|
* 线程执行函数 |
|
|
|
* @return |
|
|
|
*/ |
|
|
|
CStatus run() override { |
|
|
|
CStatus run() final { |
|
|
|
CGRAPH_FUNCTION_BEGIN |
|
|
|
CGRAPH_ASSERT_INIT(true) |
|
|
|
CGRAPH_ASSERT_NOT_NULL(pool_threads_) |
|
|
@ -91,7 +93,7 @@ protected: |
|
|
|
if (popTask(task) || popPoolTask(task) || stealTask(task)) { |
|
|
|
runTask(task); |
|
|
|
} else { |
|
|
|
std::this_thread::yield(); |
|
|
|
fatWait(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -102,7 +104,22 @@ protected: |
|
|
|
// 尝试从主线程中获取/盗取批量task,如果成功,则依次执行 |
|
|
|
runTasks(tasks); |
|
|
|
} else { |
|
|
|
std::this_thread::yield(); |
|
|
|
fatWait(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* 如果总是进入无task的状态,则开始休眠 |
|
|
|
* 休眠一定时间后,然后恢复执行状态,避免出现 |
|
|
|
*/ |
|
|
|
CVoid fatWait() { |
|
|
|
cur_empty_epoch_++; |
|
|
|
std::this_thread::yield(); |
|
|
|
if (cur_empty_epoch_ >= config_->primary_thread_busy_epoch_) { |
|
|
|
CGRAPH_UNIQUE_LOCK lk(mutex_); |
|
|
|
cv_.wait_for(lk, std::chrono::milliseconds(config_->primary_thread_empty_interval_)); |
|
|
|
cur_empty_epoch_ = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -117,6 +134,7 @@ protected: |
|
|
|
|| secondary_queue_.tryPush(std::move(task)))) { |
|
|
|
std::this_thread::yield(); |
|
|
|
} |
|
|
|
cv_.notify_one(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -164,16 +182,15 @@ protected: |
|
|
|
* 窃取的时候,仅从相邻的primary线程中窃取 |
|
|
|
* 待窃取相邻的数量,不能超过默认primary线程数 |
|
|
|
*/ |
|
|
|
for (int i = 0; i < steal_range_; i++) { |
|
|
|
for (auto& target : steal_targets_) { |
|
|
|
/** |
|
|
|
* 从线程中周围的thread中,窃取任务。 |
|
|
|
* 如果成功,则返回true,并且执行任务。 |
|
|
|
* steal 的时候,先从第二个队列里偷,从而降低触碰锁的概率 |
|
|
|
*/ |
|
|
|
int curIndex = (index_ + i + 1) % config_->default_thread_size_; |
|
|
|
if (likely((*pool_threads_)[curIndex]) |
|
|
|
&& (((*pool_threads_)[curIndex])->secondary_queue_.trySteal(task)) |
|
|
|
|| ((*pool_threads_)[curIndex])->primary_queue_.trySteal(task)) { |
|
|
|
if (likely((*pool_threads_)[target]) |
|
|
|
&& (((*pool_threads_)[target])->secondary_queue_.trySteal(task)) |
|
|
|
|| ((*pool_threads_)[target])->primary_queue_.trySteal(task)) { |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
@ -192,13 +209,12 @@ protected: |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
for (int i = 0; i < steal_range_; i++) { |
|
|
|
int curIndex = (index_ + i + 1) % config_->default_thread_size_; |
|
|
|
if (likely((*pool_threads_)[curIndex])) { |
|
|
|
bool result = ((*pool_threads_)[curIndex])->secondary_queue_.trySteal(tasks, config_->max_steal_batch_size_); |
|
|
|
for (auto& target : steal_targets_) { |
|
|
|
if (likely((*pool_threads_)[target])) { |
|
|
|
bool result = ((*pool_threads_)[target])->secondary_queue_.trySteal(tasks, config_->max_steal_batch_size_); |
|
|
|
auto leftSize = config_->max_steal_batch_size_ - tasks.size(); |
|
|
|
if (leftSize > 0) { |
|
|
|
result |= ((*pool_threads_)[curIndex])->primary_queue_.trySteal(tasks, leftSize); |
|
|
|
result |= ((*pool_threads_)[target])->primary_queue_.trySteal(tasks, leftSize); |
|
|
|
} |
|
|
|
|
|
|
|
if (result) { |
|
|
@ -216,12 +232,30 @@ protected: |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* 构造 steal 范围的 target,避免每次盗取的时候,重复计算 |
|
|
|
* @return |
|
|
|
*/ |
|
|
|
CVoid buildStealTargets() { |
|
|
|
steal_targets_.clear(); |
|
|
|
for (int i = 0; i < config_->calcStealRange(); i++) { |
|
|
|
auto target = (index_ + i + 1) % config_->default_thread_size_; |
|
|
|
steal_targets_.push_back(target); |
|
|
|
} |
|
|
|
steal_targets_.shrink_to_fit(); |
|
|
|
} |
|
|
|
|
|
|
|
private: |
|
|
|
int index_; // 线程index |
|
|
|
int steal_range_; // 偷窃的范围信息 |
|
|
|
UWorkStealingQueue primary_queue_; // 内部队列信息 |
|
|
|
UWorkStealingQueue secondary_queue_; // 第二个队列,用于减少触锁概率,提升性能 |
|
|
|
int cur_empty_epoch_ = 0; // 当前空转的轮数信息 |
|
|
|
UWorkStealingQueue<UTask> primary_queue_; // 内部队列信息 |
|
|
|
UWorkStealingQueue<UTask> secondary_queue_; // 第二个队列,用于减少触锁概率,提升性能 |
|
|
|
std::vector<UThreadPrimary *>* pool_threads_; // 用于存放线程池中的线程信息 |
|
|
|
std::vector<int> steal_targets_; // 被偷的目标信息 |
|
|
|
|
|
|
|
std::mutex mutex_; |
|
|
|
std::condition_variable cv_; |
|
|
|
|
|
|
|
friend class UThreadPool; |
|
|
|
friend class UAllocator; |
|
|
|