5 changed files with 433 additions and 0 deletions
-
221core/components/jobs/thread_pool_task_scheduler.cpp
-
106core/components/jobs/thread_pool_task_scheduler.hpp
-
57core/components/jobs/work_queue.cpp
-
46core/components/jobs/work_queue.hpp
-
3module.cmake
@ -0,0 +1,221 @@ |
|||
//
|
|||
// Created by zhaohe on 19-5-21.
|
|||
//
|
|||
|
|||
#include "thread_pool_task_scheduler.hpp"
|
|||
using namespace std; |
|||
using namespace iflytop; |
|||
using namespace core; |
|||
using namespace chrono; |
|||
|
|||
ThreadPoolTaskScheduler::ThreadPoolTaskScheduler(const string& name, int numThread) |
|||
: name(name), numThread(numThread) {} |
|||
void ThreadPoolTaskScheduler::initialize() { |
|||
for (int32_t i = 0; i < numThread; ++i) { |
|||
unique_ptr<ThreadWrapper> threadWrapper(new ThreadWrapper()); |
|||
threadWrapper->timerThread = i == 0; |
|||
threadWrapper->sleepd = false; |
|||
|
|||
ThreadWrapper* threadWrapperP = threadWrapper.get(); |
|||
threadWrapper->thread.reset(new Thread(fmt::format("{}-{}{}", "ThreadPoolTaskScheduler", name, i), |
|||
[this, threadWrapperP]() { threadProcessFunction(threadWrapperP); })); |
|||
|
|||
threads.push_back(move(threadWrapper)); |
|||
} |
|||
} |
|||
void ThreadPoolTaskScheduler::pushTask(const string& debugInfo, function<void(void)> work) { |
|||
shared_ptr<Task> newTask(new Task()); |
|||
newTask->work = work; |
|||
newTask->debugInfo = debugInfo; |
|||
tasks.enqueue(newTask); |
|||
|
|||
/************************************************/ |
|||
// 如有有正在休息的线程,只唤醒正在休息的线程即可
|
|||
// 否则唤醒全部线程,让所有线程竞争新的Task
|
|||
bool waked = false; |
|||
for (auto& threadW : threads) { |
|||
if (threadW->sleepd) { |
|||
threadW->thread->wake(); |
|||
waked = true; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (!waked) |
|||
for (auto& threadW : threads) threadW->thread->wake(); |
|||
} |
|||
|
|||
void ThreadPoolTaskScheduler::threadProcessFunction(ThreadWrapper* threadWrapper) { |
|||
shared_ptr<Task> task; |
|||
ThisThread thisThread; |
|||
while (!thisThread.getExitFlag()) { |
|||
threadWrapper->sleepd = false; |
|||
|
|||
if (tasks.try_dequeue(task)) { |
|||
if (task && task->work) { |
|||
try { |
|||
logger->debug("Do {} task", task->debugInfo); |
|||
task->work(); |
|||
} catch (const std::exception& e) { |
|||
logger->error("catch exception on Task {}\nexception:{}", task->debugInfo, e.what()); |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (threadWrapper->timerThread) { |
|||
timerProcess(); |
|||
} |
|||
|
|||
if (tasks.size_approx() != 0) { |
|||
continue; |
|||
} |
|||
|
|||
threadWrapper->sleepd = true; |
|||
if (threadWrapper->timerThread) { |
|||
sleepUntilNextTimer(); |
|||
} else { |
|||
thisThread.sleep(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/**
|
|||
* @brief Set the Interval object |
|||
* |
|||
* @param work |
|||
* @param interval_ms |
|||
* @param doItAtOnce |
|||
* @return int |
|||
*/ |
|||
int ThreadPoolTaskScheduler::setInterval(function<void(void)> work, int32_t interval_ms, bool doItAtOnce) { |
|||
return setTimer(work, interval_ms, doItAtOnce, false); |
|||
} |
|||
/**
|
|||
* @brief Set the Timeout object |
|||
* |
|||
* @param work |
|||
* @param timeout_ms |
|||
* @return int |
|||
*/ |
|||
int ThreadPoolTaskScheduler::setTimeout(function<void(void)> work, int32_t timeout_ms) { |
|||
return setTimer(work, timeout_ms, false, true); |
|||
} |
|||
/**
|
|||
* @brief 停止定时器 |
|||
* |
|||
* @param id |
|||
*/ |
|||
void ThreadPoolTaskScheduler::stopTimer(uint32_t& id) { |
|||
std::lock_guard<std::mutex> lock(lockMapAndVector); |
|||
for (auto& each : newTimers) { |
|||
if (each->id == id) each->stoped = true; |
|||
} |
|||
|
|||
for (auto& each : timers) { |
|||
auto& timer = each.second; |
|||
if (timer->id == id) timer->stoped = true; |
|||
} |
|||
|
|||
id = 0; |
|||
}; |
|||
|
|||
int ThreadPoolTaskScheduler::setTimer(function<void(void)> work, int32_t interval_ms, bool doItAtOnce, |
|||
bool doItOnlyOneTime) { |
|||
std::lock_guard<std::mutex> lock(lockMapAndVector); |
|||
shared_ptr<Timer> timer(new Timer()); |
|||
timer->doItOnlyOneTime = doItOnlyOneTime; |
|||
if (doItAtOnce) { |
|||
timer->elapsedTime = tu_steady().now(); |
|||
} else { |
|||
timer->elapsedTime = tu_steady().addms(interval_ms); |
|||
} |
|||
timer->id = timerId; |
|||
timer->interval = interval_ms; |
|||
timer->work = work; |
|||
newTimers.push_back(timer); |
|||
timerId++; |
|||
|
|||
/********************************/ |
|||
// 唤醒Timer线程
|
|||
for (auto& threadW : threads) { |
|||
if (threadW->timerThread) { |
|||
threadW->thread->wake(); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
return timer->id; |
|||
} |
|||
|
|||
void ThreadPoolTaskScheduler::timerProcess() { |
|||
vector<uint32_t> disableTimer; |
|||
|
|||
/**********************处理新Timer************/ |
|||
{ |
|||
std::lock_guard<std::mutex> lock(lockMapAndVector); |
|||
for (auto& each : newTimers) { |
|||
timers[each->id] = each; |
|||
} |
|||
newTimers.clear(); |
|||
|
|||
disableTimer.clear(); |
|||
for (auto& each : timers) { |
|||
auto& timer = each.second; |
|||
if (timer->stoped) disableTimer.push_back(each.first); |
|||
} |
|||
for (auto& each : disableTimer) timers.erase(each); |
|||
} |
|||
|
|||
/********************************************/ |
|||
auto now = tu_steady().now(); |
|||
for (auto& each : timers) { |
|||
auto& timer = each.second; |
|||
if (timer->stoped) { |
|||
continue; |
|||
} |
|||
|
|||
if (timer->hasDoneOnce && timer->doItOnlyOneTime) { |
|||
disableTimer.push_back(each.first); |
|||
continue; |
|||
} |
|||
|
|||
if (now.time_since_epoch() > timer->elapsedTime.time_since_epoch()) { |
|||
if (timer->work) timer->work(); |
|||
timer->elapsedTime = tu_steady().addms(now, timer->interval); |
|||
timer->hasDoneOnce = true; |
|||
} |
|||
} |
|||
|
|||
/********************************************/ |
|||
} |
|||
|
|||
void ThreadPoolTaskScheduler::sleepUntilNextTimer() { |
|||
ThisThread thisThread; |
|||
time_point<steady_clock> nextwakeTime; |
|||
bool first = false; |
|||
bool hasSetedNextwakeTime = false; |
|||
for (auto& each : timers) { |
|||
auto& timer = each.second; |
|||
if (timer->stoped) { |
|||
continue; |
|||
} |
|||
|
|||
if (first) { |
|||
nextwakeTime = timer->elapsedTime; |
|||
first = true; |
|||
hasSetedNextwakeTime = true; |
|||
} |
|||
|
|||
if (timer->elapsedTime < nextwakeTime) { |
|||
nextwakeTime = timer->elapsedTime; |
|||
hasSetedNextwakeTime = true; |
|||
} |
|||
} |
|||
|
|||
if (hasSetedNextwakeTime) { |
|||
int32_t sleepTime = tu_steady().dToMs(tu_steady().now() - nextwakeTime); |
|||
thisThread.sleepForMs(sleepTime); |
|||
} else { |
|||
thisThread.sleep(); |
|||
} |
|||
} |
@ -0,0 +1,106 @@ |
|||
//
|
|||
// Created by zhaohe on 19-5-21.
|
|||
//
|
|||
|
|||
#pragma once
|
|||
#include <fstream>
|
|||
#include <iostream>
|
|||
#include <list>
|
|||
#include <map>
|
|||
#include <memory>
|
|||
#include <memory>
|
|||
#include <mutex>
|
|||
#include <queue>
|
|||
#include <set>
|
|||
#include <sstream>
|
|||
#include <string>
|
|||
#include <vector>
|
|||
// #include "zwtimecpp/core/base/object.hpp"
|
|||
#include "iflytopcpp/core/spdlogfactory/logger.hpp"
|
|||
#include "iflytopcpp/core/thread/thread.hpp"
|
|||
#include "iflytopcpp/core/basic/concurrentqueue/concurrentqueue.h"
|
|||
#include "iflytopcpp/core/components/time_util.hpp"
|
|||
|
|||
#define CODE_LOCATION (fmt::format("{}:{}", __FILE__, __LINE__))
|
|||
|
|||
namespace iflytop { |
|||
namespace core { |
|||
using namespace std; |
|||
using namespace moodycamel; |
|||
using namespace chrono; |
|||
/**
|
|||
* 线程池 |
|||
* 任务调度 |
|||
* 线程池 |
|||
* 定时任务 |
|||
*/ |
|||
class ThreadPoolTaskScheduler { |
|||
ENABLE_LOGGER(ThreadPoolTaskScheduler) |
|||
|
|||
private: |
|||
class ThreadWrapper { |
|||
public: |
|||
unique_ptr<Thread> thread; |
|||
bool sleepd = false; |
|||
bool timerThread = false; |
|||
private: |
|||
}; |
|||
|
|||
class Task { |
|||
public: |
|||
function<void(void)> work; |
|||
string debugInfo; |
|||
|
|||
private: |
|||
}; |
|||
|
|||
class Timer { |
|||
public: |
|||
uint32_t id; |
|||
int32_t interval; //周期
|
|||
bool doItOnlyOneTime = false; //是否运行一次
|
|||
time_point<steady_clock> elapsedTime; //下次执行时间
|
|||
function<void(void)> work; //回调
|
|||
bool stoped = false; //已经停止
|
|||
bool hasDoneOnce = false; //已经执行过一次
|
|||
private: |
|||
}; |
|||
|
|||
private: |
|||
vector<unique_ptr<ThreadWrapper>> threads; |
|||
string name; |
|||
int numThread = 0; |
|||
ConcurrentQueue<shared_ptr<Task>> tasks; |
|||
std::mutex lock_; |
|||
|
|||
/**********************timer**********************/ |
|||
map<uint32_t, shared_ptr<Timer>> timers; |
|||
uint32_t timerId = {1}; |
|||
vector<shared_ptr<Timer>> newTimers; |
|||
shared_ptr<Timer> nextTimer; |
|||
atomic_bool timerStateUpdate = {false}; |
|||
std::mutex lockMapAndVector; |
|||
|
|||
public: |
|||
ThreadPoolTaskScheduler(const string& name, int num); |
|||
void initialize(); |
|||
void pushTask(const string& debugInfo, function<void(void)> work); |
|||
|
|||
int setInterval(function<void(void)> work, int32_t interval_ms, |
|||
bool doItAtOnce = false); |
|||
int setTimeout(function<void(void)> work, int32_t timeout_ms); |
|||
void stopTimer(uint32_t& id); |
|||
|
|||
~ThreadPoolTaskScheduler() { |
|||
// for (auto& thread : threads) thread->join();
|
|||
} |
|||
|
|||
private: |
|||
int setTimer(function<void(void)> work, int32_t interval_ms, bool doItAtOnce, |
|||
bool doItOnlyOneTime); |
|||
void threadProcessFunction(ThreadWrapper*threadWrapper); |
|||
void timerProcess(); |
|||
void sleepUntilNextTimer(); |
|||
}; |
|||
} |
|||
} |
@ -0,0 +1,57 @@ |
|||
/*
|
|||
* File: work_queue.hpp |
|||
* Project: worker_queue |
|||
* File Created: Thursday, 18th October 2018 5:23:19 pm |
|||
* Author: zhaohe (1013909206@qq.com) |
|||
* ----- |
|||
* Last Modified: Thursday, 18th October 2018 5:23:25 pm |
|||
* Modified By: zhaohe (1013909206@qq.com>) |
|||
* ----- |
|||
* Copyright 2017 - 2018 zwsd, zwsd |
|||
*/ |
|||
#include "work_queue.hpp"
|
|||
|
|||
#include <fstream>
|
|||
#include <functional>
|
|||
#include <iostream>
|
|||
#include <list>
|
|||
#include <map>
|
|||
#include <memory>
|
|||
#include <mutex>
|
|||
#include <string>
|
|||
#include <thread>
|
|||
#include <vector>
|
|||
|
|||
#include "iflytopcpp/core/basic/concurrentqueue/blockingconcurrentqueue.h"
|
|||
#include "iflytopcpp/core/thread/thread.hpp"
|
|||
|
|||
using namespace iflytop; |
|||
using namespace core; |
|||
using namespace std; |
|||
|
|||
WorkQueue::WorkQueue(string name) { |
|||
is_running_ = true; |
|||
thread_.reset(new Thread(name, [this]() { |
|||
while (1) { |
|||
if (!is_running_) { |
|||
break; |
|||
} |
|||
function<void(void)> call_; |
|||
queue_.wait_dequeue(call_); |
|||
if (call_) call_(); |
|||
} |
|||
})); |
|||
}; |
|||
void WorkQueue::clear() { |
|||
function<void(void)> call_; |
|||
while (queue_.try_dequeue(call_)) { |
|||
/*clear queue*/ |
|||
} |
|||
}; |
|||
size_t WorkQueue::getSize() { return queue_.size_approx(); } |
|||
void WorkQueue::enQueue(function<void(void)> func) { queue_.enqueue(func); } |
|||
WorkQueue::~WorkQueue() { |
|||
is_running_ = false; |
|||
queue_.enqueue(nullptr); |
|||
if (thread_) thread_->join(); |
|||
} |
@ -0,0 +1,46 @@ |
|||
/*
|
|||
* File: work_queue.hpp |
|||
* Project: worker_queue |
|||
* File Created: Thursday, 18th October 2018 5:23:19 pm |
|||
* Author: zhaohe (1013909206@qq.com) |
|||
* ----- |
|||
* Last Modified: Thursday, 18th October 2018 5:23:25 pm |
|||
* Modified By: zhaohe (1013909206@qq.com>) |
|||
* ----- |
|||
* Copyright 2017 - 2018 zwsd, zwsd |
|||
*/ |
|||
#pragma once
|
|||
#include <fstream>
|
|||
#include <functional>
|
|||
#include <iostream>
|
|||
#include <list>
|
|||
#include <map>
|
|||
#include <memory>
|
|||
#include <mutex>
|
|||
#include <string>
|
|||
#include <thread>
|
|||
#include <vector>
|
|||
|
|||
#include "iflytopcpp/core/basic/concurrentqueue/blockingconcurrentqueue.h"
|
|||
#include "iflytopcpp/core/thread/thread.hpp"
|
|||
|
|||
namespace iflytop { |
|||
namespace core { |
|||
using namespace std; |
|||
class WorkQueue { |
|||
bool is_running_ = false; |
|||
unique_ptr<Thread> thread_; |
|||
moodycamel::BlockingConcurrentQueue<function<void(void)>> queue_; |
|||
|
|||
public: |
|||
WorkQueue(string name); |
|||
void clear(); |
|||
size_t getSize(); |
|||
void enQueue(function<void(void)> func); |
|||
~WorkQueue(); |
|||
|
|||
private: |
|||
}; |
|||
} // namespace core
|
|||
|
|||
} // namespace iflytop
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue