215 lines
6.3 KiB
C++
215 lines
6.3 KiB
C++
|
/*
|
|||
|
* Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
|
|||
|
*
|
|||
|
* This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
|
|||
|
*
|
|||
|
* Use of this source code is governed by MIT license that can be found in the
|
|||
|
* LICENSE file in the root of the source tree. All contributing project authors
|
|||
|
* may be found in the AUTHORS file in the root of the source tree.
|
|||
|
*/
|
|||
|
|
|||
|
#include <memory>
|
|||
|
#include "TaskExecutor.h"
|
|||
|
#include "Poller/EventPoller.h"
|
|||
|
#include "Util/onceToken.h"
|
|||
|
#include "Util/TimeTicker.h"
|
|||
|
|
|||
|
using namespace std;
|
|||
|
|
|||
|
namespace toolkit {
|
|||
|
|
|||
|
ThreadLoadCounter::ThreadLoadCounter(uint64_t max_size, uint64_t max_usec) {
|
|||
|
_last_sleep_time = _last_wake_time = getCurrentMicrosecond();
|
|||
|
_max_size = max_size;
|
|||
|
_max_usec = max_usec;
|
|||
|
}
|
|||
|
|
|||
|
void ThreadLoadCounter::startSleep() {
|
|||
|
lock_guard<mutex> lck(_mtx);
|
|||
|
_sleeping = true;
|
|||
|
auto current_time = getCurrentMicrosecond();
|
|||
|
auto run_time = current_time - _last_wake_time;
|
|||
|
_last_sleep_time = current_time;
|
|||
|
_time_list.emplace_back(run_time, false);
|
|||
|
if (_time_list.size() > _max_size) {
|
|||
|
_time_list.pop_front();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void ThreadLoadCounter::sleepWakeUp() {
|
|||
|
lock_guard<mutex> lck(_mtx);
|
|||
|
_sleeping = false;
|
|||
|
auto current_time = getCurrentMicrosecond();
|
|||
|
auto sleep_time = current_time - _last_sleep_time;
|
|||
|
_last_wake_time = current_time;
|
|||
|
_time_list.emplace_back(sleep_time, true);
|
|||
|
if (_time_list.size() > _max_size) {
|
|||
|
_time_list.pop_front();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
int ThreadLoadCounter::load() {
|
|||
|
lock_guard<mutex> lck(_mtx);
|
|||
|
uint64_t totalSleepTime = 0;
|
|||
|
uint64_t totalRunTime = 0;
|
|||
|
_time_list.for_each([&](const TimeRecord &rcd) {
|
|||
|
if (rcd._sleep) {
|
|||
|
totalSleepTime += rcd._time;
|
|||
|
} else {
|
|||
|
totalRunTime += rcd._time;
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
if (_sleeping) {
|
|||
|
totalSleepTime += (getCurrentMicrosecond() - _last_sleep_time);
|
|||
|
} else {
|
|||
|
totalRunTime += (getCurrentMicrosecond() - _last_wake_time);
|
|||
|
}
|
|||
|
|
|||
|
uint64_t totalTime = totalRunTime + totalSleepTime;
|
|||
|
while ((_time_list.size() != 0) && (totalTime > _max_usec || _time_list.size() > _max_size)) {
|
|||
|
TimeRecord &rcd = _time_list.front();
|
|||
|
if (rcd._sleep) {
|
|||
|
totalSleepTime -= rcd._time;
|
|||
|
} else {
|
|||
|
totalRunTime -= rcd._time;
|
|||
|
}
|
|||
|
totalTime -= rcd._time;
|
|||
|
_time_list.pop_front();
|
|||
|
}
|
|||
|
if (totalTime == 0) {
|
|||
|
return 0;
|
|||
|
}
|
|||
|
return (int) (totalRunTime * 100 / totalTime);
|
|||
|
}
|
|||
|
|
|||
|
////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
Task::Ptr TaskExecutorInterface::async_first(TaskIn task, bool may_sync) {
|
|||
|
return async(std::move(task), may_sync);
|
|||
|
}
|
|||
|
|
|||
|
void TaskExecutorInterface::sync(const TaskIn &task) {
|
|||
|
semaphore sem;
|
|||
|
auto ret = async([&]() {
|
|||
|
onceToken token(nullptr, [&]() {
|
|||
|
//通过RAII原理防止抛异常导致不执行这句代码
|
|||
|
sem.post();
|
|||
|
});
|
|||
|
task();
|
|||
|
});
|
|||
|
if (ret && *ret) {
|
|||
|
sem.wait();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void TaskExecutorInterface::sync_first(const TaskIn &task) {
|
|||
|
semaphore sem;
|
|||
|
auto ret = async_first([&]() {
|
|||
|
onceToken token(nullptr, [&]() {
|
|||
|
//通过RAII原理防止抛异常导致不执行这句代码
|
|||
|
sem.post();
|
|||
|
});
|
|||
|
task();
|
|||
|
});
|
|||
|
if (ret && *ret) {
|
|||
|
sem.wait();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
TaskExecutor::TaskExecutor(uint64_t max_size, uint64_t max_usec) : ThreadLoadCounter(max_size, max_usec) {}
|
|||
|
|
|||
|
//////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
TaskExecutor::Ptr TaskExecutorGetterImp::getExecutor() {
|
|||
|
auto thread_pos = _thread_pos;
|
|||
|
if (thread_pos >= _threads.size()) {
|
|||
|
thread_pos = 0;
|
|||
|
}
|
|||
|
|
|||
|
TaskExecutor::Ptr executor_min_load = _threads[thread_pos];
|
|||
|
auto min_load = executor_min_load->load();
|
|||
|
|
|||
|
for (size_t i = 0; i < _threads.size(); ++i) {
|
|||
|
++thread_pos;
|
|||
|
if (thread_pos >= _threads.size()) {
|
|||
|
thread_pos = 0;
|
|||
|
}
|
|||
|
|
|||
|
auto th = _threads[thread_pos];
|
|||
|
auto load = th->load();
|
|||
|
|
|||
|
if (load < min_load) {
|
|||
|
min_load = load;
|
|||
|
executor_min_load = th;
|
|||
|
}
|
|||
|
if (min_load == 0) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
_thread_pos = thread_pos;
|
|||
|
return executor_min_load;
|
|||
|
}
|
|||
|
|
|||
|
vector<int> TaskExecutorGetterImp::getExecutorLoad() {
|
|||
|
vector<int> vec(_threads.size());
|
|||
|
int i = 0;
|
|||
|
for (auto &executor : _threads) {
|
|||
|
vec[i++] = executor->load();
|
|||
|
}
|
|||
|
return vec;
|
|||
|
}
|
|||
|
|
|||
|
void TaskExecutorGetterImp::getExecutorDelay(const function<void(const vector<int> &)> &callback) {
|
|||
|
std::shared_ptr<vector<int> > delay_vec = std::make_shared<vector<int>>(_threads.size());
|
|||
|
shared_ptr<void> finished(nullptr, [callback, delay_vec](void *) {
|
|||
|
//此析构回调触发时,说明已执行完毕所有async任务
|
|||
|
callback((*delay_vec));
|
|||
|
});
|
|||
|
int index = 0;
|
|||
|
for (auto &th : _threads) {
|
|||
|
std::shared_ptr<Ticker> delay_ticker = std::make_shared<Ticker>();
|
|||
|
th->async([finished, delay_vec, index, delay_ticker]() {
|
|||
|
(*delay_vec)[index] = (int) delay_ticker->elapsedTime();
|
|||
|
}, false);
|
|||
|
++index;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void TaskExecutorGetterImp::for_each(const function<void(const TaskExecutor::Ptr &)> &cb) {
|
|||
|
for (auto &th : _threads) {
|
|||
|
cb(th);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
size_t TaskExecutorGetterImp::getExecutorSize() const {
|
|||
|
return _threads.size();
|
|||
|
}
|
|||
|
|
|||
|
size_t TaskExecutorGetterImp::addPoller(const string &name, size_t size, int priority, bool register_thread, bool enable_cpu_affinity) {
|
|||
|
auto cpus = thread::hardware_concurrency();
|
|||
|
size = size > 0 ? size : cpus;
|
|||
|
for (size_t i = 0; i < size; ++i) {
|
|||
|
auto full_name = name + " " + to_string(i);
|
|||
|
auto cpu_index = i % cpus;
|
|||
|
EventPoller::Ptr poller(new EventPoller(full_name));
|
|||
|
poller->runLoop(false, register_thread);
|
|||
|
poller->async([cpu_index, full_name, priority, enable_cpu_affinity]() {
|
|||
|
// 设置线程优先级
|
|||
|
ThreadPool::setPriority((ThreadPool::Priority)priority);
|
|||
|
// 设置线程名
|
|||
|
setThreadName(full_name.data());
|
|||
|
// 设置cpu亲和性
|
|||
|
if (enable_cpu_affinity) {
|
|||
|
setThreadAffinity(cpu_index);
|
|||
|
}
|
|||
|
});
|
|||
|
_threads.emplace_back(std::move(poller));
|
|||
|
}
|
|||
|
return size;
|
|||
|
}
|
|||
|
|
|||
|
}//toolkit
|