C++武艺修炼--基于C++17实现后台异步执行多任务

06-01 325阅读

该功能是基于C++17实现后台异步执行多任务。

在实际开发中,经常会遇到开启多个异步线程,去执行不同的任务。比如我有一个需求,每20秒去读取某个文件,每50秒去查询数据库某个字段,每30分钟去删除某个数据库或文件。那么最直观的思路就是,开启三个异步线程,分别去执行各自的任务,我也问过很多人,他们也都是这么做的。有一个有开发十多年的C++工程师,也是这么说的,他说现在的CPU性能这么高,压根不需要考虑开多个线程影响性能的问题。

我听完后,陷入了沉思。我沉思的原因不是思考他说的话是对是错。而是思考,是不是工作后,大家对开发的执着度及热情都极度低靡。感觉完成任务完成需求就行,至于怎么完成,完全不重要。而且领导也不懂,压根不关注怎么完成的,反而那些执着于性能和简洁性的人,会被领导觉得不行,代码量少,哈哈。你和他说前期封装轮子可能需要点时间,后期需求省时间。领导说:“我不管你怎么实现,我只要结果,我明天就要看到第一个完整的功能,后天看到第二个,大后天看到第三个”。

如果你按照自己的想法,造轮子就得两天,最后一天把三个任务都放入轮子中,也是三天正好把任务干完。但是前两天可得煎熬了。领导说:“你这两天的任务怎么没完成,没完成怎么也不加班!!!你这个人工作态度严重不行,太差劲了!!!” 于是你和领导解释,说是第三天肯定能把任务都写完。领导说:“现在不是第三天交任务的问题,而是你最近两天没完成任务,也不加班,是你的工作态度的问题!!!你的工作态度出现严重问题,我现在怀疑你到底能不能胜任这份工作!!!你写一份检讨报告,明天在单位读一下,引以为戒!!!”

于是乎,有一些人,按照领导的要求,每天写一个需求,写完了给领导看,领导乐呵呵,说:“你这个人,能力强,工作态度好,尽心尽责,年底的优秀员工就是你啦!!!” 听到领导的认可,你也乐呵呵,你还可能会升职涨薪。那这时的你还专注性能吗?还专注代码的简洁性,低耦合性吗?还会专注写出高质量代码吗?

反正我还是坚持做自己。引用一下罗永浩的金句 “彪悍的人生,不需要解释!”

C++武艺修炼--基于C++17实现后台异步执行多任务

好啦,开始分析这个需求。有三个不同任务需求,分别需要不同时间循环触发,首先需要确定的是,这三个任务本身不是死循环任务,如果任务本生是死循环的话,那么它自生就得单独开一个异步线程去执行。

那么可不可以把这三个任务放入一个异步线程呢?让这一个线程去循环执行不同的任务呢。思路确定了,那么就开始设计实现步骤啦。

这三个任务可以放入容器中,在线程中依次遍历,并执行。

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 
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

相关阅读

目录[+]

取消
微信二维码
微信二维码
支付宝二维码