C++中的chrono使用及实现异步定时器timer

C++中的chrono使用及实现异步定时器timer

由于C++标准中没有定时器,本文使用C++11相关语法并进行以下封装
大致流程为定时器启动时创建两个线程分别用于时间处理和函数回调操作;
m_timerThread 每个定时器周期都会向queue中写入sn并触发条件变量的notify,sn每次notify时会自动+1,除非该定时器执行了stop或定时器重新start了;
m_workerThread 会在条件变量被notify后读取queue中的sn,如果sn符合条件则执行callback,除非该定时器执行了stop或callback无效;
设计两个线程的目的是为了尽可能的避免单线程工作中callback处理时间的不确定性影响到定时器触发的波动;
另外start中对sleep时间进行了一定的校正,即在原来基础上 -0.5ms这是考虑到sleep之外的其他动作可能导致的耗时而做的简单修正;


本封装对外提供接口start和stop,并禁止定时器拷贝和赋值;
调用start时会自动结束掉正在运行的timer(如果timer没有stop)并重新开始使用最新的参数来计时和触发新的callback;
可以使用的接口原型如下
void start(int intervalmillis, std::function callback);
void stop();
 

//mytimer.hpp
#ifndef __SWTIMER_H__
#define __SWTIMER_H__

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#if 0
    extern long long getSteadyMillis();
    #define DEBUG_TIMER_BEGIN  std::cout<<__func__<<" begin:"<(std::chrono::milliseconds(1000));
        m_callbackFunc = std::function(nullptr);
        create();
    }

    ~SWTimer() {
        destroy();
        // std::cout << "~cpptimer" << std::endl;
    }

    SWTimer(const SWTimer&) = delete;
    SWTimer &operator=(const SWTimer&) = delete;
private:
    void create() {
        DEBUG_TIMER_BEGIN
        if (m_timerMainThreadAlive) {
            return;
        }
        m_timerMainThreadAlive = true;
        m_timerThread = std::thread([this]() { //lambda
            do {
                if (timerWait()) {
                    doNotify(); // notify work thread
                }
            } while (m_timerMainThreadAlive);
        });

        m_workerThread = std::thread([this]() {
            do {
                workWait(); // wait for timer notify
                doCallback();
            } while (m_timerMainThreadAlive);
        });
        DEBUG_TIMER_END
    }
    void destroy() {
        m_timerMainThreadAlive = false;
        stop();
        m_workerCond.notify_all();
        m_timerCond.notify_all();
        if (m_timerThread.joinable()) {
            m_timerThread.join();
        }
        if (m_workerThread.joinable()) {
            m_workerThread.join();
        }
    }

public:
    void start(int intervalmillis, std::function callback) {
        //callback: std::bind(funcname, parameters...);
        std::chrono::milliseconds interval_millis(intervalmillis);
        std::chrono::microseconds interval_micros = std::chrono::duration_cast(interval_millis);
        std::chrono::microseconds adjust_micros(500);
        std::chrono::microseconds sleep_micros(interval_micros - adjust_micros);
        DEBUG_TIMER_BEGIN
        {
            MuxGuard g(m_MuxLock);
            while (!m_workQueue.empty()) {
                m_workQueue.pop();
            }
            m_timerStarted = true;
            m_callbackSn = 0;
            m_callbackFunc = callback;
            m_sleepMicros = sleep_micros;
            m_timerQueue.push(m_callbackSn);
            if (!m_timerMainThreadAlive) {
                create();
            }
        }
        m_timerCond.notify_one();
        DEBUG_TIMER_END
    }

    bool timerWait() {
        DEBUG_TIMER_BEGIN
        MuxUniqLck tul(m_MuxLock);
        uint32_t sn = 0;
        if (!m_timerQueue.empty()) {
            while (!m_timerQueue.empty()) {
                m_timerQueue.pop();
            }
            // std::cout<<"return false queue, "<(m_nowTimePoint-m_startTimePoint);
        // std::cout<<"delta:"< callback = std::function(nullptr);
        {
            MuxGuard g(m_MuxLock);
            uint32_t sn = 0;
            while (!m_workQueue.empty()) {
                sn = m_workQueue.front();
                m_workQueue.pop();
            };
            // std::cout<<"sn:"<(nullptr);
        }
        DEBUG_TIMER_END
    }

private:
    typedef std::chrono::duration> DurationMicrosT;
    mutable std::mutex m_MuxLock;
    using MuxGuard = std::lock_guard;
    using MuxUniqLck = std::unique_lock;
    std::condition_variable m_timerCond;
    std::condition_variable m_workerCond;
    std::thread m_timerThread;
    std::thread m_workerThread;
    std::atomic m_timerMainThreadAlive;
    std::atomic m_timerStarted;

    std::atomic m_callbackSn;
    std::function m_callbackFunc = std::function(nullptr);
    std::chrono::microseconds m_sleepMicros;
    std::queue m_workQueue;
    std::queue m_timerQueue;
    std::chrono::steady_clock::time_point m_startTimePoint;
    std::chrono::steady_clock::time_point m_nowTimePoint;
    DurationMicrosT m_deltaMicros;
};

#endif //__SWTIMER_H__

 

测试demo代码

//mytimer.cpp
/*****************************************
* Copyright (C) 2020 * Ltd. All rights reserved.
* File name   : mytimer.cpp
* Created date: 2020-05-07 00:35:00
*******************************************/

#include 
#include 
#include 
#include 
#include "mytimer.hpp"

using namespace std;
long long g_totalCnt = 0;
long long g_starttime = 0;
long long g_lasttime = 0;
long long g_warncount = 0;

long long getSteadyMillis()
{
    //CLOCK_REALTIME:系统相对时间,从UTC 1970-1-1 0:0:0开始计时,更改系统时间会更改获取的值;
    //CLOCK_MONOTONIC:系统绝对时间/单调时间,为系统重启到现在的时间,更改系统时间对它没有影响;
    //CLOCK_PROCESS_CPUTIME_ID:本进程到当前代码系统CPU花费的时间;
    //CLOCK_THREAD_CPUTIME_ID:本线程到当前代码系统CPU花费的时间;
    struct timespec ts {};
    (void)clock_gettime(CLOCK_MONOTONIC, &ts);
    long long milliseconds = (ts.tv_sec*1000) + (ts.tv_nsec/1000000);
    return milliseconds;
}

long long getSystemMillis()
{
    struct timespec ts {};
    (void)clock_gettime(CLOCK_REALTIME, &ts);
    long long milliseconds = (ts.tv_sec*1000) + (ts.tv_nsec/1000000);
    return milliseconds;
}

void timerCallbackFunc(std::string &&info, int number) {
    g_totalCnt += 1;
    long long millis = getSteadyMillis();
    if (g_starttime == 0) {
        g_starttime = millis;
    }
    if (g_lasttime == 0) {
        g_lasttime = millis;
    }
    long long interval = millis - g_lasttime;
    long long spent = millis - g_starttime;
    if (interval < 50) {
        std::cout<<"###### "<<__func__<<" warning: unexpected interval="<start(100, std::bind(timerCallbackFunc,"periodic timer!", 1));
    std::this_thread::sleep_for(std::chrono::seconds(3));
    ptimer->stop();

    int i = 0;
    std::string info;
    for (i = 0; i< 20000; i++) {
        info = "hi";
        g_lasttime = getSteadyMillis();
        ptimer->start(100, std::bind(timerCallbackFunc, info.c_str(), i));
        std::this_thread::sleep_for(std::chrono::seconds(1));
        ptimer->stop();
    }

    g_lasttime = getSteadyMillis();
    ptimer->start(1000, std::bind(timerCallbackFunc,"periodic timer!", 1));
    std::this_thread::sleep_for(std::chrono::seconds(6));
    ptimer->stop();

    std::this_thread::sleep_for(std::chrono::seconds(3));
    if (ptimer != NULL) {
        delete ptimer;
        ptimer = NULL;
    }
    time_t now = time(0);
    std::cout<<"at "<

你可能感兴趣的:(#,Linux_env,#,04std_C++)