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
原文链接:https://www.stubbornhuang.com/903/
发布于:2020年08月26日 17:02:50
修改于:2023年06月26日 22:18:10
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
评论
51