高并发定时任务调度系统

项目描述

轻量级、高精度定时器系统,用于解决多线程环境下任务的延时执行与周期性调度问题。该系统采用时间轮(Timing Wheel)算法优化时间复杂度,利用双向链表管理任务队列,支持毫秒级精度的任务插入、删除、启动与停止。系统通过互斥锁(Mutex)保证线程安全,有效避免了多线程竞争导致的数据不一致问题,适用于需要精准控制任务执行时机的嵌入式或后台服务场景。

核心功能

任务管理 :实现了任务的动态插入(InsertTimer)、按名称删除(DeleteTask)、链表清空及状态打印功能。

精准调度 :支持毫秒级精度的定时任务,通过系统常量 TIMER_MS(20ms)控制刷新频率,平衡了精度与性能。

并发控制 : 提供了定时器的启动(StartTimer)与停止(StopTimer)接口,能够处理大量并发任务的调度需求。

状态监控: 提供了链表打印(PrintTimer)功能,实时监控当前待执行任务列表及剩余时间。

技术亮点

算法优化 (时间轮思想): 采用差值法存储时间(每个节点存储与前一节点的时间差),将时间复杂度从 O(n) 降低至 O(1) 或 O(log n) 级别(取决于插入逻辑),显著提升了大量任务下的插入与刷新效率。

线程安全设计 : 在所有关键操作(插入、删除、刷新)中使用 std::lock_guard 进行加锁,确保了在多线程环境下的数据一致性与安全性。

资源管理 : 利用 std::list 的动态内存特性,避免了固定数组的内存浪费;通过 std::this_thread::sleep_for 实现非阻塞式等待,保证了主线程的响应性。

异常处理: 设计了完善的错误码机制(ErrNo),对同名任务插入、空指针调用等异常情况进行捕获与处理,增强了系统的健壮性。

项目文件图

run.sh

复制代码
#
#       简介:定时器测试程序编译脚本
#       平台:linux
#       可执行测试程序:timer
#       测试log:timer.log
#

#!/bin/bash

g++ test.cpp timer.cpp -o timer

echo "==============$(date)============" >> timer.log

./timer >> timer.log

test.cpp

复制代码
/* 
 * 定时器测试程序
 */

#include <iostream>
#include "timer.h"

void func(void *param)
{
    std::cout << (char *)param << std::endl;
    return;
}

int main()
{
    /* 插入定时任务 */
    Timer t;
    t.InsertTimer(100, (void*)func, (void*)"t1", "t1");
    t.InsertTimer(300, (void*)func, (void*)"t2", "t2");
    t.InsertTimer(400, (void*)func, (void*)"t3", "t3");
    t.InsertTimer(5000, (void*)func, (void*)"t4", "t4");
    t.InsertTimer(10000, (void*)func, (void*)"t5", "t5");
    t.InsertTimer(300, (void*)func, (void*)"t6", "t6");
    t.InsertTimer(100, (void*)func, (void*)"t7", "t7");
    t.InsertTimer(80, (void*)func, (void*)"t8", "t8");
    t.InsertTimer(800, (void*)func, (void*)"t9", "t9");
    t.InsertTimer(10000, (void*)func, (void*)"t10", "t10");

    /* 打印定时器链上的定时任务 */
    t.PrintTimer();

    /* 启动定时器 */
    std::cout << "start timer..." << std::endl;
    t.StartTimer();

    return 0;
}

timer.log

复制代码
==============Fri Mar 13 19:37:21 CST 2026============
TimerList:
t8:80
t1:100
t7:100
t2:300
t6:300
t3:400
t9:800
t4:5000
t5:10000
t10:10000
start timer...
t8
t1
t7
t2
t6
t3
t9
t4
t5
t10

timer.h

复制代码
/* 
 * 变更历史:
 * 2026-03-13  cxb  创建该文件.
 */

/*
 * @file  Timer.h
 * @brief
 * 功能:定时器用于定时执行任务.
 */

#ifndef __TIMER_H__
#define __TIMER_H__

#include <iostream>
#include <list>
#include <mutex>
#include <thread>
#include <string>

#define TIMER_MS 20   /* 定时器链表刷新时间间隔(ms) */

/* 错误号 */
typedef enum
{
    OK = 0,
    ERROR
} ErrNo;

class Timer
{
private:
    /* 不支持拷贝与赋值构造 */
    Timer(const Timer &timer);
    Timer operator=(const Timer &timer);

    /* 定时器链成员 */
    struct TimerMember
    {
        long ms;                  /* 定时时间 */
        std::string name;         /* 名字 */
        void *func;               /* 执行函数 */
        void *param;              /* 执行函数参数 */

        TimerMember(unsigned long ms, void *func, void *param, std::string name):
            ms(ms),
            func(func),
            param(param),
            name(name)
        {};
    };

    std::list<struct TimerMember> TimerList;   /* 定时器链 */
    std::list<struct TimerMember> ExecList;    /* 待执行链 */
    std::mutex TimerLock;                      /* 定时器链锁 */

    ErrNo DeleteTimer();                       /* 删除定时器链上的就绪定时器 */
    ErrNo InsertExec();                        /* 插入就绪定时器到待执行链 */
    ErrNo ExecTimer();                         /* 触发就绪定时器 */
    ErrNo FlushTimer();                        /* 刷新定时器链上的定时器时间 */
    ErrNo ClearList(std::list<struct TimerMember> &List); /* 清空链表 */
    bool  ListIsEmpty(std::list<struct TimerMember> &List);/* 链表判空 */

public:
    ErrNo InsertTimer(long ms, void *func, void *param, std::string name); /* 插入定时器到定时器链 */
    ErrNo StartTimer();                         /* 启动所有定时器 */
    ErrNo StopTimer();                          /* 停止所有定时器 */
    ErrNo DeleteTask(std::string name);         /* 删除指定定时器 */
    ErrNo PrintTimer();                         /* 打印定时器链上的所有定时器 */

    Timer()
    {
        TimerList.emplace_back(0 ,nullptr, nullptr, "");
        ExecList.emplace_back(0 ,nullptr, nullptr, "");
        TimerList.clear();
        ExecList.clear();
    };
    ~Timer()
    {
        TimerList.clear();
        ExecList.clear();
    };
};

#endif

timer.cpp

复制代码
/* 
 * 变更历史:
 * 2024-03-13  cxb  创建文件
 */

/*
 * @file  Timer.c
 * @brief
 * 功能:实现定时器功能接口
 */

#include "timer.h"

/* 定时任务 */
typedef void (*TimerFunc)(void *);

/* 判断链表是否为空 */
bool Timer::ListIsEmpty(std::list<struct TimerMember> &List)
{
    if(List.size() == 0)
        return true;
    return false;
}

/* 插入定时任务到定时器链 */
ErrNo Timer::InsertTimer(long ms, void *func, void *param, std::string name)
{
    ErrNo status = OK;
    std::lock_guard<std::mutex> lock(TimerLock);

    /* 校验是否包含同名任务 */
    for(auto it = TimerList.begin(); it != TimerList.end(); it++)
    {
        if(it->name.compare(name) == 0)
        {
            std::cout << name << " has excited" << std::endl;
            status = ERROR;
            return status;
        }
    }

    /* 定时器链为空是插入定时任务 */
    if(ListIsEmpty(TimerList))
    {
        TimerList.emplace(TimerList.end(), ms, func, param, name);
        return status;
    }

    /* 定时器链非空且插入到链中间 */
    long AddMs = 0, TmpMs = 0;
    for(auto it = TimerList.begin(); it != TimerList.end(); it++)
    {
        TmpMs = AddMs;
        AddMs += it->ms;
        if(AddMs > ms)
        {
            it->ms -= (ms - TmpMs);
            TimerList.emplace(it, ms - TmpMs, func, param, name);
            return status;
        }
    }

    /* 定时任务插入链尾 */
    TimerList.emplace(TimerList.end(), ms - AddMs, func, param, name);
    return status;
}

/* 清除定时器链表中的就绪任务 */
ErrNo Timer::DeleteTimer()
{
    ErrNo status = OK;
    if(ListIsEmpty(TimerList))
        return status;
    auto it = TimerList.begin();
    while(it != TimerList.end())
    {
        if(it->ms == 0)
        {
            TimerList.erase(it);
        }
        else
        {
            break;
        }
        it = TimerList.begin();
    }

    return status;
}

/* 将定时器中的就绪任务插入到待执行链 */
ErrNo Timer::InsertExec()
{
    ErrNo status = OK;
    if(ListIsEmpty(TimerList) || (TimerList.front().ms != 0))
    {
        return status;
    }

    for(auto it = TimerList.begin(); it != TimerList.end(); it++)
    {
        /* 从链表头开始第一个等待时间不为0之前的任务均为就绪任务 */
        if(it->ms == 0)
        {
            ExecList.insert(ExecList.end(), *it);
        }
        else
        {
            break;
        }
    }

    return status;
}

/* 清空链表 */
ErrNo Timer::ClearList(std::list<struct TimerMember> &List)
{
    ErrNo status = OK;
    List.clear();
    return status;
}

/* 运行待执行链上的就绪任务 */
ErrNo Timer::ExecTimer()
{
    ErrNo status = OK;
    int tmp = 0;

    /* 运行就绪任务 */
    for(auto it = ExecList.begin(); it != ExecList.end(); it++)
    {
        if(it->func != nullptr)
        {
            TimerFunc f = (TimerFunc)it->func;
            f(it->param);
        }
    }

    /* 清空就绪链*/
    status = ClearList(ExecList);
    return status;
}

/* 刷新定时器链表上的定时任务的定时时间 */
ErrNo Timer::FlushTimer()
{
    ErrNo status = OK;
    long TmpMs = TIMER_MS;
    for(auto it = TimerList.begin(); it != TimerList.end(); it++)
    {
        if(TmpMs == 0)
            break;

        if(it->ms < TmpMs)
        {
            /* 超时打印并更新定时时间*/
            if(it->ms != 0)
            {
                it->ms = 0;
                TmpMs -= it->ms;
                std::cout << it->name << "超时" << TmpMs - it->ms << "ms" << std::endl;
            }
        }
        else
        {
            /* 更新为超时时间*/
            it->ms -= TmpMs;
            TmpMs = 0;
        }
    }

    return status;
}

/* 启动定时器 */
ErrNo Timer::StartTimer()
{
    ErrNo status = OK;
    for(;;)
    {
        std::lock_guard<std::mutex> lock(TimerLock);
        if(ListIsEmpty(TimerList))
            break;

        /* 每隔TIMER_MS刷新并执行定时任务 */
        std::this_thread::sleep_for(std::chrono::microseconds(TIMER_MS));

        /* 刷新定时*/
        FlushTimer();

        /* 运行并清除定时任务 */
        InsertExec();
        ExecTimer();
        DeleteTimer();
    }

    return status;
}

/* 停止定时器 */
ErrNo Timer::StopTimer()
{
    ErrNo status = OK;
    std::lock_guard<std::mutex> lock(TimerLock);

    /* 清空定时器链和待执行链 */
    status = ClearList(ExecList);
    status = ClearList(TimerList);
    return status;
}

/* 删除定时任务 */
ErrNo Timer::DeleteTask(std::string name)
{
    ErrNo status = OK;
    std::lock_guard<std::mutex> lock(TimerLock);

    /* 删除待执行链上的任务 */
    for(auto it = ExecList.begin(); it != ExecList.end(); it++)
    {
        if(it->name.compare(name))
        {
            ExecList.erase(it);
        }
    }

    /* 删除定时器器链上的任务 */
    for(auto it = TimerList.begin(); it != TimerList.end(); it++)
    {
        if(it->name.compare(name))
        {
            TimerList.erase(it);
        }
    }
    return status;
}

/* 打印定时器链上的定时任务 */
ErrNo Timer::PrintTimer()
{
    ErrNo status = OK;
    long TimerMs = 0;
    std::lock_guard<std::mutex> lock(TimerLock);
    std::cout << "TimerList:" << std::endl;
    for(auto it = TimerList.begin(); it != TimerList.end(); it++)
    {
        TimerMs += it->ms;
        std::cout << it->name << ":" << TimerMs << std::endl;
    }

    return status;
} 
相关推荐
biter down2 小时前
C++ stringstream 简单介绍:告别字符数组,安全高效的字符串与数据转换利器
开发语言·c++
C+-C资深大佬2 小时前
C++ 模板进阶
开发语言·c++·算法
耶叶2 小时前
C++:拷贝构造函数
开发语言·c++
努力中的编程者2 小时前
栈和队列(C语言底层实现栈)
c语言·开发语言·数据结构·c++
HAPPY酷2 小时前
Linux 网络命令速查:告别 `ifconfig`,拥抱 `ip`
linux·网络·tcp/ip
前端不太难2 小时前
OpenClaw 如何运行 Claw 资源文件
c++·开源·游戏引擎
我不听你讲话2 小时前
Nginx核心功能
linux·服务器·python
草莓熊Lotso2 小时前
MySQL 数据类型核心指南:选型、实战与避坑
linux·运维·服务器·数据库·c++·人工智能·mysql
co_wait2 小时前
【C++ STL】排序算法
开发语言·c++·排序算法