C++定时器CTimer的实现

C++系列

  • 第一章 C++单例模式
  • 第二章 数据流对象CData
  • 第三章 基于基础数据类型的封解包模板
  • 第四章 FIFO单链列表
  • 第五章 C++线程
  • 第六章 C++线程池
  • 第七章 定时器
  • 第八章 消息中心
  • 第九章 网络访问器
  • 第十章 HttpClient
  • 第十一章 FTPClient
  • 第十二章 Socket客户端
  • 第十三章 Socket服务端
  • 第十四章 WebSocket

大部分章节不会详细讲解,基本是以源码形式展现给大家,欢迎各路大侠搬砖和点评^_^,详细源码查看Github

前言

有过使用Objective-C、Java等语言开发项目的同学会发现,网络或社区有存在众多的开源库或组件。个人在使用C++11进行项目开发时,想找一些比较完善、系统化的基本功能库却很少,比如定时器。
这里,主要利用thread、mutex、condition_variable_any、function来实现定时器,可现实同步、异步、单次、循序执行任务。代码中附带了简单的注释,若有疑问或建议欢迎留言。

更新时间更新内容
2021.03.171、新增时间戳相关静态接口;2、优化代码

CTimer.hpp

//
//  CTimer.hpp
//  ZJCrossCpp
//
//  Created by eafy on 2020/10/5.
//  Copyright © 2020 ZJ. All rights reserved.
//

#ifndef CTimer_hpp
#define CTimer_hpp

#include <stdio.h>
#include <functional>
#include <chrono>
#include <thread>
#include <atomic>
#include <mutex>
#include <string>
#include <condition_variable>
#include "CDefType.hpp"

ZJ_NAMESPACE_BEGIN

class CTimer
{
public:
    CTimer(const std::string sTimerName = "");   //构造定时器,附带名称
    ~CTimer();
    
    /**
     开始运行定时器

     @param msTime 延迟运行(单位ms)
     @param task 任务函数接口
     @param bLoop 是否循环(默认执行1次)
     @param async 是否异步(默认异步)
     @return true:已准备执行,否则失败
     */
    bool Start(unsigned int msTime, std::function<void()> task, bool bLoop = false, bool async = true);
    
    /**
     取消定时器,同步定时器无法取消(若任务代码已执行则取消无效)
     */
    void Cancel();
    
    /**
     同步执行一次
     #这个接口感觉作用不大,暂时现实在这里

     @param msTime 延迟时间(ms)
     @param fun 函数接口或lambda代码块
     @param args 参数
     @return true:已准备执行,否则失败
     */
    template<typename callable, typename... arguments>
    bool SyncOnce(int msTime, callable&& fun, arguments&&... args) {
        std::function<typename std::result_of<callable(arguments...)>::type()> task(std::bind(std::forward<callable>(fun), std::forward<arguments>(args)...)); //绑定任务函数或lambda成function
        return Start(msTime, task, false, false);
    }
    
    /**
     异步执行一次任务
     
     @param msTime 延迟及间隔时间(毫秒)
     @param fun 函数接口或lambda代码块
     @param args 参数
     @return true:已准备执行,否则失败
     */
    template<typename callable, typename... arguments>
    bool AsyncOnce(int msTime, callable&& fun, arguments&&... args) {
        std::function<typename std::result_of<callable(arguments...)>::type()> task(std::bind(std::forward<callable>(fun), std::forward<arguments>(args)...));
        
        return Start(msTime, task, false);
    }
    
    /**
     异步执行一次任务(默认延迟10毫秒后执行)
     
     @param fun 函数接口或lambda代码块
     @param args 参数
     @return true:已准备执行,否则失败
     */
    template<typename callable, typename... arguments>
    bool AsyncOnce(callable&& fun, arguments&&... args) {
        std::function<typename std::result_of<callable(arguments...)>::type()> task(std::bind(std::forward<callable>(fun), std::forward<arguments>(args)...));
        
        return Start(1, task, false);
    }
    
    
    /**
     异步循环执行任务

     @param msTime 延迟及间隔时间(毫秒)
     @param fun 函数接口或lambda代码块
     @param args 参数
     @return true:已准备执行,否则失败
     */
    template<typename callable, typename... arguments>
    bool AsyncLoop(int msTime, callable&& fun, arguments&&... args) {
        std::function<typename std::result_of<callable(arguments...)>::type()> task(std::bind(std::forward<callable>(fun), std::forward<arguments>(args)...));
        
        return Start(msTime, task, true);
    }
    
public:
    /// 获取时间戳(毫秒)
    static uint64_t Timestamp();
    
    /// 获取格式化时间
    static std::string FormatTime(const std::string sFormat = "%Y-%m-%d %H:%M:%S");

    /// 获取UTC时间
    static struct tm *UTCTime(long long secTime = 0);

    /// 获取UTC时间(秒)
    static int64_t UTCTime();

    /// 获取与0时区的时差(以秒为单位)
    static int TimeDifFrimGMT();
    
private:
    void DeleteThread();    //删除任务线程

public:
    int m_nCount = 0;   //循环次数
    int m_nTag = 0;     //定时器标签
    
private:
    std::string m_sName;   //定时器名称
    
    std::atomic_bool m_bExpired;       //装载的任务是否已经过期
    std::atomic_bool m_bTryExpired;    //装备让已装载的任务过期(标记)
    std::atomic_bool m_bLoop;          //是否循环
    
    std::thread *m_Thread = nullptr;
    std::mutex m_ThreadLock;
    std::condition_variable_any m_ThreadCon;
};

ZJ_NAMESPACE_END
#endif /* CTimer_hpp */

CTimer.cpp

//
//  CTimer.cpp
//  ZJCrossCpp
//
//  Created by eafy on 2020/10/5.
//  Copyright © 2020 ZJ. All rights reserved.
//

#include "CTimer.hpp"
#include <future>
#include <time.h>
#include <sys/time.h>
#include <stdlib.h>

ZJ_NAMESPACE_BEGIN

CTimer::CTimer(const std::string sTimerName):m_bExpired(true), m_bTryExpired(false), m_bLoop(false)
{
    m_sName = sTimerName;
}

CTimer::~CTimer()
{
    m_bTryExpired = true;   //尝试使任务过期
    DeleteThread();
}

bool CTimer::Start(unsigned int msTime, std::function<void()> task, bool bLoop, bool async)
{
    if (!m_bExpired || m_bTryExpired) return false;  //任务未过期(即内部仍在存在或正在运行任务)
    m_bExpired = false;
    m_bLoop = bLoop;
    m_nCount = 0;

    if (async) {
        DeleteThread();
        m_Thread = new std::thread([this, msTime, task]() {
            if (!m_sName.empty()) {
#if (defined(__ANDROID__) || defined(ANDROID))      //兼容Android
                pthread_setname_np(pthread_self(), m_sName.c_str());
#elif defined(__APPLE__)                            //兼容苹果系统
                pthread_setname_np(m_sName.c_str());    //设置线程(定时器)名称
#endif
            }
            
            while (!m_bTryExpired) {
                m_ThreadCon.wait_for(m_ThreadLock, std::chrono::milliseconds(msTime));  //休眠
                if (!m_bTryExpired) {
                    task();     //执行任务

                    m_nCount ++;
                    if (!m_bLoop) {
                        break;
                    }
                }
            }
            
            m_bExpired = true;      //任务执行完成(表示已有任务已过期)
            m_bTryExpired = false;  //为了下次再次装载任务
        });
    } else {
        std::this_thread::sleep_for(std::chrono::milliseconds(msTime));
        if (!m_bTryExpired) {
            task();
        }
        m_bExpired = true;
        m_bTryExpired = false;
    }
    
    return true;
}

void CTimer::Cancel()
{
    if (m_bExpired || m_bTryExpired || !m_Thread) {
        return;
    }
    
    m_bTryExpired = true;
}

void CTimer::DeleteThread()
{
    if (m_Thread) {
        m_ThreadCon.notify_all();   //休眠唤醒
        m_Thread->join();           //等待线程退出
        delete m_Thread;
        m_Thread = nullptr;
    }
}

#pragma mark -

uint64_t CTimer::Timestamp()
{
    uint64_t msTime = 0;

#if defined(__APPLE__)  //iOS
    if (__builtin_available(iOS 10.0, *)) {
        struct timespec abstime;
        clock_gettime(CLOCK_REALTIME, &abstime);
        msTime = ((uint64_t)abstime.tv_sec) * 1000 + ((uint64_t)abstime.tv_nsec) / 1000000;
    } else {
        struct timeval abstime;
        gettimeofday(&abstime, NULL);
        msTime = ((uint64_t)abstime.tv_sec) * 1000 + ((uint64_t)abstime.tv_usec) / 1000;
    }
#else
    struct timespec abstime;
    clock_gettime(CLOCK_REALTIME, &abstime);

    msTime = ((uint64_t)abstime.tv_sec) * 1000 + ((uint64_t)abstime.tv_nsec) / 1000000;   //需要强制转long long
#endif

    return msTime;
}

std::string CTimer::FormatTime(const std::string sFormat)
{
    time_t timep;
    time (&timep);

    char tmp[64];
    strftime(tmp, sizeof(tmp), sFormat.c_str(), localtime(&timep));

    return std::string(tmp);
}

struct tm *CTimer::UTCTime(long long secTime)
{
    time_t timep;
    if (secTime) {
        timep = secTime;
    } else {
        time (&timep);
    }

    struct tm *data = gmtime(&timep);
    data->tm_year += 1900;
    data->tm_mon += 1;

    return data;
}

int64_t CTimer::UTCTime()
{
    int64_t msTime = 0;

#if defined(__APPLE__)  //iOS
    if (__builtin_available(iOS 10.0, *)) {
        struct timespec abstime;
        clock_gettime(CLOCK_REALTIME, &abstime);
        msTime = ((int64_t)abstime.tv_sec) * 1000 + ((int64_t)abstime.tv_nsec) / 1000000;
    } else {
        struct timeval abstime;
        gettimeofday(&abstime, NULL);
        msTime = ((int64_t)abstime.tv_sec) * 1000 + ((int64_t)abstime.tv_usec) / 1000;
    }
#else
    struct timespec abstime;
    clock_gettime(CLOCK_REALTIME, &abstime);

    msTime = (int64_t)abstime.tv_sec;
#endif

    return msTime;
}

int CTimer::TimeDifFrimGMT()
{
    time_t now = time(NULL);
    struct tm *gmTime = gmtime(&now);
    if (gmTime) {
        return (int)difftime(now, mktime(gmTime));
    }

    return 0;
}



ZJ_NAMESPACE_END


用法:

  • 方式1:
	CTimer *pTimer = new CTimer("定时器1");
	pTimer->AsyncOnce(10, [](void *userData) {		//延迟10毫秒执行1次
		CPCenterCtl *pCenterCtl = static_cast<CPCenterCtl*>(userData);    //CPCenterCtl是当前类
		if (pCenterCtl) {
	 	CPrintf("这是一个定时器");
	 	}
	}, this);
  • 方式2:
	void CPCenterCtl::didHeartbeatThread(void *arg);		//定时器任务函数
    
	CTimer *pTimer = new CTimer("定时器2");
	pTimer->AsyncLoop(10, didHeartbeatThread, this);	//异步循环执行,间隔时间10毫秒
  • 方式3:
	CTimer *pTimer = new CTimer("定时器3");
	pTimer->AsyncLoop(10, [](JMCPCenterCtl *self) {
		printf(“这是一个10毫秒触发的定时器”)}, this);	//异步循环执行,间隔时间10毫秒
  • 方式4:
    int a = 1;
    int b = 2;
    int sum = 0;
    CTimer *pTimer = new CTimer("定时器4");
    pTimer->AsyncLoop(1000, [](void *self, int a, int b, int *sum) {
        *sum = a + b + *sum;
        printf("累加 sum += a + b + *sum: %d\n", *sum);
    }, this, a, b , &sum);    //异步循环执行,间隔时间1秒

打印:
	累加 sum += a + b + *sum: 3
	累加 sum += a + b + *sum: 6
	累加 sum += a + b + *sum: 9
	累加 sum += a + b + *sum: 12
  • 23
    点赞
  • 157
    收藏
    觉得还不错? 一键收藏
  • 25
    评论
在 Linux 下使用 C 编程语言实现定时器可以通过使用 POSIX 定时器库来实现。 首先,你需要包含头文件 `time.h` 和 `signal.h`: ```c #include <time.h> #include <signal.h> ``` 然后,定义一个全局变量来存储定时器 ID: ```c timer_t timerid; ``` 接下来,你可以编写一个处理定时器信号的函数,例如: ```c void timer_handler(int signum) { // 处理定时器触发事件 } ``` 在主函数中,你需要创建一个定时器,并设置它的属性和定时器处理函数: ```c int main() { struct sigevent sev; struct itimerspec its; struct sigaction sa; // 定义定时器处理函数 sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = timer_handler; sigemptyset(&sa.sa_mask); sigaction(SIGRTMIN, &sa, NULL); // 创建定时器 sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIGRTMIN; sev.sigev_value.sival_ptr = &timerid; timer_create(CLOCK_REALTIME, &sev, &timerid); // 设置定时器属性 its.it_value.tv_sec = 1; // 第一次触发的秒数 its.it_value.tv_nsec = 0; // 第一次触发的纳秒数 its.it_interval.tv_sec = 1; // 以后每次触发的间隔秒数 its.it_interval.tv_nsec = 0; // 以后每次触发的间隔纳秒数 // 启动定时器 timer_settime(timerid, 0, &its, NULL); // 循环等待定时器触发事件 while (1) { // ... } return 0; } ``` 以上代码中,`timer_create()` 函数用于创建一个定时器,`timer_settime()` 函数用于启动定时器。你可以根据实际需求修改定时器的触发时间和间隔。 当定时器触发时,`timer_handler()` 函数将被调用,你可以在该函数中编写处理定时器事件的代码。 这只是一个简单的示例,你可以根据你的具体需求进行更复杂的定时器操作。希望这个回答能对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值