C++武艺修炼--基于C++17实现后台异步执行多任务
该功能是基于C++17实现后台异步执行多任务。
在实际开发中,经常会遇到开启多个异步线程,去执行不同的任务。比如我有一个需求,每20秒去读取某个文件,每50秒去查询数据库某个字段,每30分钟去删除某个数据库或文件。那么最直观的思路就是,开启三个异步线程,分别去执行各自的任务,我也问过很多人,他们也都是这么做的。有一个有开发十多年的C++工程师,也是这么说的,他说现在的CPU性能这么高,压根不需要考虑开多个线程影响性能的问题。
我听完后,陷入了沉思。我沉思的原因不是思考他说的话是对是错。而是思考,是不是工作后,大家对开发的执着度及热情都极度低靡。感觉完成任务完成需求就行,至于怎么完成,完全不重要。而且领导也不懂,压根不关注怎么完成的,反而那些执着于性能和简洁性的人,会被领导觉得不行,代码量少,哈哈。你和他说前期封装轮子可能需要点时间,后期需求省时间。领导说:“我不管你怎么实现,我只要结果,我明天就要看到第一个完整的功能,后天看到第二个,大后天看到第三个”。
如果你按照自己的想法,造轮子就得两天,最后一天把三个任务都放入轮子中,也是三天正好把任务干完。但是前两天可得煎熬了。领导说:“你这两天的任务怎么没完成,没完成怎么也不加班!!!你这个人工作态度严重不行,太差劲了!!!” 于是你和领导解释,说是第三天肯定能把任务都写完。领导说:“现在不是第三天交任务的问题,而是你最近两天没完成任务,也不加班,是你的工作态度的问题!!!你的工作态度出现严重问题,我现在怀疑你到底能不能胜任这份工作!!!你写一份检讨报告,明天在单位读一下,引以为戒!!!”
于是乎,有一些人,按照领导的要求,每天写一个需求,写完了给领导看,领导乐呵呵,说:“你这个人,能力强,工作态度好,尽心尽责,年底的优秀员工就是你啦!!!” 听到领导的认可,你也乐呵呵,你还可能会升职涨薪。那这时的你还专注性能吗?还专注代码的简洁性,低耦合性吗?还会专注写出高质量代码吗?
反正我还是坚持做自己。引用一下罗永浩的金句 “彪悍的人生,不需要解释!”
好啦,开始分析这个需求。有三个不同任务需求,分别需要不同时间循环触发,首先需要确定的是,这三个任务本身不是死循环任务,如果任务本生是死循环的话,那么它自生就得单独开一个异步线程去执行。
那么可不可以把这三个任务放入一个异步线程呢?让这一个线程去循环执行不同的任务呢。思路确定了,那么就开始设计实现步骤啦。
这三个任务可以放入容器中,在线程中依次遍历,并执行。
1.但是我还想让线程循环时多睡觉,比如任务执行分别是,5s,10s,13s。
那么我想每此循环睡5s,再分别检测执行。后来发现实现起来有点难,读者有没有大佬,欢迎给出好的实现思路。
2.第二种方法是找5s,10s,13s的最小公因数,以此为基准,进行循环遍历。
3.第三种就是索性每秒循环遍历一次,谁的时间到了,就执行谁。
第一种方法我写了很久,反正没写出来,急需一个算法大佬帮忙优化。
第二种方法直接弃用了,感觉画蛇添足,没啥意思。
第三种方法最直接,也最没啥挑战性,但是迫不得已,还是选用这种方法啦。
其实不管用哪种方法,整体实现思路都一样,只不过是最后循环遍历实现的细节不一样而已。那么就一起来捋一下思路。
1.需要有一个任务管理类进行记录要实现的功能和函数。
2.需要一个管理类进行存储任务,并实现其所有任务添加、开始和结束等。
3.需要一个单例管理,方便多个不同地方的任务添加。
4.进行调用测试。
以下代码是根据第三种方来进行实现:
1.实现任务管理类进行记录要实现的功能和函数。
2.实现管理类进行存储任务,并实现其所有任务添加、开始和结束等。
#ifndef FUNMANAGE_H
#define FUNMANAGE_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct Task {
int iID = 0;
Task(int iINID, std::function pfun) :
iID(iINID)
{
func = std::make_shared(std::move(pfun));
isUsing = std::make_shared();
}
Task() = delete;
public:
void runFuncByCounter(const int iNum) noexcept
{
if((++m_iCounter) >= iNum)
{
runFunc();
m_iCounter = 0;
}
}
void runFunc() noexcept
{
dowithAtomic(*func);
}
public:
bool dowithAtomic(std::function func) noexcept
{
while(isUsing->load(std::memory_order_acquire))
std::this_thread::yield();
isUsing->store(true,std::memory_order_release);
if(func)
func();
isUsing->store(false,std::memory_order_release);
return true;
}
private:
std::shared_ptr func;
std::shared_ptr isUsing;
int m_iCounter = 0;
};
struct FunManageBase
{
int generateTimeBasedID(){
auto now = std::chrono::system_clock::now();
std::time_t now_time = std::chrono::system_clock::to_time_t(now);
return static_cast(now_time);
}
int gcd(int a, int b)
{
while (b != 0) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}
int gcd_multiple(const std::vector& numbers)
{
if (numbers.empty()) return 0; // 如果数组为空,返回0
int result = numbers[0];
for (size_t i = 1; i first);
++iter;
}
return retVec;
}
};
struct FunManage : FunManageBase
{
//这里 应该返回一个IP, 让用户根据IP自己管理
template
int pushFun(int iSecTime, F&& f, Args&&... args) noexcept(noexcept(std::forward(f)(std::forward(args)...)))
{
auto task = [f = std::forward(f), args_tuple = std::make_tuple(std::forward(args)...)]() mutable {
return std::apply(f, args_tuple);
};
std::unique_lock lock(queue_mutex);
const int iRetID = generateTimeBasedID();
tasks.emplace(iSecTime, Task{iRetID, std::move(task)});
return iRetID;
}
//开始全部任务
void startAll()noexcept
{
if(isStart)
return;
std::thread threadWeak([this]{
auto iter = tasks.begin();
int iBegTime = 0;
if(iter != tasks.end())
iBegTime = iter->first;
while(isStart)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
while(iter != tasks.end())
{
iter->second.runFuncByCounter(iter->first);
++iter;
}
iter = tasks.begin();
}
});
isStart = true;
threadWeak.detach();
}
//结束全部任务
void stopAll()noexcept
{
isStart = false;
}
//移除任务 通过ID
bool removeTaskByID(const int iID)noexcept
{
auto iter = tasks.begin();
while(iter != tasks.end())
{
if(iter->second.iID == iID)
{
if(iter->second.dowithAtomic({}))
{
tasks.erase(iter);
return true;
}
}
++iter;
}
return false;
}
///后期大家想添加接口随便添加就行
///比如,通过ID,单独开启/关闭 某一个或者某几个任务。
///这里俺就不写啦,比较简单,也不难。
private:
std::multimap tasks;
std::mutex queue_mutex;
bool isStart = false;
};
#endif // FUNMANAGE_H
以下实现的是:
3.实现一个单例管理,方便多个不同地方的任务添加。
有关该类的.h头文件的实现:
#ifndef TIMERFUNMANAGE_H
#define TIMERFUNMANAGE_H
写一个开启独立线程
///通过定时器
///处理多个回调函数
///实现在FunManage.h文件
#include "FunManage.h"
class TimerFunManage
{
public:
static TimerFunManage *getInstance();
FunManage& getFunManage();
private:
TimerFunManage();
~TimerFunManage();
private:
static TimerFunManage* TimerFun_instance;
FunManage m_FunManage;
};
#endif // TIMERFUNMANAGE_H
有关该类的.cpp源文件的实现:
#include "TimerFunManage.h"
TimerFunManage* TimerFunManage::TimerFun_instance{};
TimerFunManage* TimerFunManage::getInstance()
{
if(!TimerFun_instance)
TimerFun_instance = new TimerFunManage();
return TimerFun_instance;
}
FunManage &TimerFunManage::getFunManage()
{
return m_FunManage;
}
TimerFunManage::TimerFunManage()
{
}
TimerFunManage::~TimerFunManage()
{
m_FunManage.stopAll();
}
下面进行第四步调用测试:
std::string s_str = "kkkkkkkk";
int main()
{
auto& pManage = TimerFunManage::getInstance()->getFunManage();
int iiii = 99999;
auto lamda_AAA = [iiii]() {
std::cout
std::cout
std::cout 

