1 基于C++11特性的微小定时器 - TinyTimer

Github地址:https://github.com/HW140701/TinyTimer

只包含一个头文件的基于C++11特性的微小定时器实现类 -TinyTimer,支持
- 支持同步/异步执行定时器任务;
- 支持中途中断定时器任务,可参考Windows Api的SetTimer和KillTimer;
- 支持多种任务函数类型

代码:
- TinyTimer.hpp

#ifndef TINY_TIMER_H
#define TINY_TIMER_H

#include <functional>
#include <chrono>
#include <thread>
#include <atomic>
#include <memory>
#include <mutex>
#include <condition_variable>
#include <memory>
#include <string>

class TinyTimer
{
public:
    typedef std::shared_ptr<TinyTimer> ptr;
    virtual~TinyTimer() 
    {
        KillTimer();
    }


    TinyTimer() :m_bExpired(true), m_bTryExpired(false), m_bLoopExecute(false)
    {

    }

    TinyTimer(const TinyTimer& t) {
        m_bExpired = t.m_bExpired.load();
        m_bTryExpired = t.m_bTryExpired.load();
    }

public:
    //!
    //! @brief  设置定时器
    //!
    //! @param  interval - 定时器执行间隔
    //! @param  task - 任务函数
    //! @param  bLoop - 是否循环
    //! @param  async - 是否异步执行
    //!
    //! @return 执行结果
    //!
    bool SetTimer(int interval, std::function<void()> task, bool bLoop = false, bool async = true)
    {
        if (!m_bExpired || m_bTryExpired)
            return false;

        m_bExpired = false;
        m_bLoopExecute = bLoop;
        m_LoopCount = 0;

        // 如果是异步执行
        if (async)
        {
            if (m_Thread != nullptr)
                m_Thread.reset();

            m_Thread = std::make_shared<std::thread>(
                ([this, interval, task]() {
                while (!m_bTryExpired)
                {
                    std::this_thread::sleep_for(std::chrono::milliseconds(interval));

                    task();

                    m_LoopCount++;

                    if (!m_bLoopExecute)
                    {
                        break;
                    }
                }
                {
                    std::lock_guard<std::mutex> locker(m_ThreadMutex);
                    m_bExpired = true;
                    m_bTryExpired = false;
                    m_ExpiredConditionVar.notify_one();
                }
            })
            );
            m_Thread->detach();
        }
        // 如果是同步执行
        else
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(interval));
            if (!m_bTryExpired) {
                task();
            }
            m_bExpired = true;
            m_bTryExpired = false;
        }

        return true;
    }

    //!
    //! @brief  杀死定时器
    //!
    void KillTimer()
    {
        if (m_bExpired || m_bTryExpired || m_Thread == nullptr)
        {
            return;
        }

        m_bTryExpired = true;
        {
            std::unique_lock<std::mutex> locker(m_ThreadMutex);
            m_ExpiredConditionVar.wait(locker, [this] {return m_bExpired == true; });
            if (m_bExpired == true) {
                m_bTryExpired = false;
            }
        }
    }

    //!
    //! @brief  异步延迟执行一次定时器
    //!
    //! @param  interval - 定时器执行间隔
    //! @param  fun - 任务函数
    //!
    //! @return 执行结果
    //!
    template<typename callable, typename... arguments>
    bool AsyncOnceExecute(int interval, 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 SetTimer(interval, task, false);
    }


    //!
    //! @brief  异步定时循环执行定时器
    //!
    //! @param  interval - 定时器执行间隔
    //! @param  fun - 任务函数
    //!
    //! @return 执行结果
    //!
    template<typename callable, typename... arguments>
    bool AsyncLoopExecute(int interval, 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 SetTimer(interval, task, true);
    }

    //!
    //! @brief  同步执行一次定时器
    //!
    //! @param  interval - 定时器执行间隔
    //! @param  fun - 任务函数
    //!
    //! @return 执行结果
    //!
    template<typename callable, typename... arguments>
    bool SyncOnceExecute(int interval, 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 SetTimer(interval, task, false, false);
    }

private:
    std::atomic_bool m_bExpired;
    std::atomic_bool m_bTryExpired;
    std::atomic_bool m_bLoopExecute;
    std::mutex m_ThreadMutex;
    std::condition_variable m_ExpiredConditionVar;
    std::shared_ptr<std::thread> m_Thread;
    unsigned int m_LoopCount = 0;
};


#endif // !TINY_TIMER_H

2 使用示例

2.1 静态/全局作为任务函数

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

#include "TinyTimer.hpp"

using namespace std;

void Print()
{
    std::cout << "定时器全局函数Print执行" << std::endl;
}


int main()
{
    TinyTimer::ptr tinyTimer = std::make_shared<TinyTimer>();

    // 延迟1秒执行1次静态/全局函数
    tinyTimer->AsyncOnceExecute(1000, Print);
    tinyTimer->KillTimer();

    // 循环执行静态/全局函数,按Q键杀死定时器
    int a = 0;
    while (true)
    {
        // 在此处填入需要循环的代码
        if (a == 0)
        {
            tinyTimer->AsyncLoopExecute(1, Print);
        }

        if (_kbhit()) // 如果有按键被按下
        {
            if (_getch() == 'q') //如果按下了q键则跳出循环
            {
                tinyTimer->KillTimer();
                break;
            }

        }
    }

    getchar();
    return 0;
}

2.2 Lambda表达式作为任务函数

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

#include "TinyTimer.hpp"

using namespace std;

int main()
{
    TinyTimer::ptr tinyTimer = std::make_shared<TinyTimer>();

    // 延迟1秒执行lambda函数表达式
    tinyTimer->AsyncOnceExecute(1000, []() {
        std::cout << "Lambda函数执行" << std::endl;
    });
    tinyTimer->KillTimer();

    getchar();
    return 0;
}

2.3 类成员函数做为任务函数

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

#include "TinyTimer.hpp"

using namespace std;

void Print()
{
    std::cout << "定时器全局函数Print执行" << std::endl;
}


class Task
{
public:
    Task() {

    };

    ~Task() {

    };

    void TaskRun()
    {
        std::cout << "Task::TaskRun()函数执行" << std::endl;
    };
};


int main()
{
    TinyTimer::ptr tinyTimer = std::make_shared<TinyTimer>();

    // 延迟1秒执行1次类成员函数
    Task taskObj;
    std::function<void(void)> taskRunFunc = std::bind(&Task::TaskRun, taskObj);
    tinyTimer->AsyncOnceExecute(1000, taskRunFunc);
    tinyTimer->KillTimer();

    getchar();
    return 0;
}

3 TinyTimer更新(2021.06.01)

3.1 新增特性

  • 支持即时退出异步子线程,修复上一个版本停止定时器需要等到下一次循环才可以停止定时器,导致阻塞主线程,如果定时器休眠时间过长会一直阻塞主线程

修改后的版本使用条件变量wait_for进行定时操作,并可根据条件及时唤醒条件变量执行退出操作!

3.2 修改后的代码

#ifndef TINY_TIMER_H
#define TINY_TIMER_H

#include <functional>
#include <chrono>
#include <thread>
#include <atomic>
#include <memory>
#include <mutex>
#include <condition_variable>
#include <memory>
#include <string>

class TinyTimer
{
public:
    typedef std::shared_ptr<TinyTimer> ptr;
    virtual~TinyTimer() 
    {
        KillTimer();
    }


    TinyTimer() :m_bExpired(true), m_bTryExpired(false), m_bLoopExecute(false)
    {

    }

    TinyTimer(const TinyTimer& t) {
        m_bExpired = t.m_bExpired.load();
        m_bTryExpired = t.m_bTryExpired.load();
    }

public:
    //!
    //! @brief  设置定时器
    //!
    //! @param  interval - 定时器执行间隔
    //! @param  task - 任务函数
    //! @param  bLoop - 是否循环
    //! @param  async - 是否异步执行
    //!
    //! @return 执行结果
    //!
    bool SetTimer(int interval, std::function<void()> task, bool bLoop = false, bool async = true)
    {
        if (!m_bExpired || m_bTryExpired)
            return false;

        m_bExpired = false;
        m_bLoopExecute = bLoop;
        m_LoopCount = 0;

        // 如果是异步执行
        if (async)
        {
            if (m_Thread != nullptr)
                m_Thread.reset();

            m_Thread = std::make_shared<std::thread>(
                ([this, interval, task]() {
                while (!m_bTryExpired)
                {
                    std::unique_lock<std::mutex> lk(m_ThreadMutex);
                    if (m_ExpiredConditionVar.wait_for(lk, std::chrono::milliseconds(interval), [this]() {return m_bTryExpired == true; }))
                    {
                        break;
                    }
                    else
                    {
                        task();

                        m_LoopCount++;

                        if (!m_bLoopExecute)
                        {
                            break;
                        }
                    }
                }
                m_bExpired = true;
                m_bTryExpired = false;
            })
            );
            m_Thread->detach();
        }
        // 如果是同步执行
        else
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(interval));
            if (!m_bTryExpired) {
                task();
            }
            m_bExpired = true;
            m_bTryExpired = false;
        }

        return true;
    }

    //!
    //! @brief  杀死定时器
    //!
    void KillTimer()
    {
        if (m_bExpired || m_bTryExpired || m_Thread == nullptr)
        {
            return;
        }

        m_bTryExpired = true;

        m_ExpiredConditionVar.notify_one();
    }

    //!
    //! @brief  异步延迟执行一次定时器
    //!
    //! @param  interval - 定时器执行间隔
    //! @param  fun - 任务函数
    //!
    //! @return 执行结果
    //!
    template<typename callable, typename... arguments>
    bool AsyncOnceExecute(int interval, 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 SetTimer(interval, task, false);
    }


    //!
    //! @brief  异步定时循环执行定时器
    //!
    //! @param  interval - 定时器执行间隔
    //! @param  fun - 任务函数
    //!
    //! @return 执行结果
    //!
    template<typename callable, typename... arguments>
    bool AsyncLoopExecute(int interval, 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 SetTimer(interval, task, true);
    }

    //!
    //! @brief  同步执行一次定时器
    //!
    //! @param  interval - 定时器执行间隔
    //! @param  fun - 任务函数
    //!
    //! @return 执行结果
    //!
    template<typename callable, typename... arguments>
    bool SyncOnceExecute(int interval, 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 SetTimer(interval, task, false, false);
    }

private:
    std::atomic_bool m_bExpired;
    std::atomic_bool m_bTryExpired;
    std::atomic_bool m_bLoopExecute;
    std::mutex m_ThreadMutex;
    std::condition_variable m_ExpiredConditionVar;
    std::shared_ptr<std::thread> m_Thread;
    unsigned int m_LoopCount = 0;
};


#endif // !TINY_TIMER_H

参考

如果您觉得对您有帮助,可以请站长喝一杯咖啡哦!

记得在赞赏备注里写上您的昵称

您可在本站资助名单中查看你的打赏记录哦!

支付宝扫一扫

微信扫一扫

金额随意,礼清义重

当前分类随机文章推荐

全站随机文章推荐

关于本站站长 StubbornHuang
我的开源项目 – 支持C++11特性的定时器TinyTimer-StubbornHuang Blog纵使晴明无雨色,入云深处亦沾衣。