对于windows 有SetTimer,KillTimer相关的API,本文主要考虑跨平台接口,而c++11本身没有提供现成的接口,所以需要自定义实现。
定时器timer是多线程编程中经常设计到的工具类,原理如下:
创建一个新线程
在那个线程里等待
等待指定时长后做任务
这里用C++11实现了一个简单易用的定时器,包含两种模式:
周期性定时任务执行
单次延时任务执行
timer.hpp
#ifndef _TIMER_H_
#define _TIMER_H_
#include <functional>
#include <chrono>
#include <thread>
#include <atomic>
#include <memory>
#include <mutex>
#include <condition_variable>
class Timer
{
public:
Timer(): _expired(true), _try_to_expire(false)
{}
Timer(const Timer& timer)
{
_expired = timer._expired.load();
_try_to_expire = timer._try_to_expire.load();
}
~Timer()
{
stop();
}
void start(int interval, std::function<void()> task)
{
// is started, do not start again
if (_expired == false)
return;
// start async timer, launch thread and wait in that thread
_expired = false;
std::thread([this, interval, task]() {
while (!_try_to_expire)
{
// sleep every interval and do the task again and again until times up
std::this_thread::sleep_for(std::chrono::milliseconds(interval));
task();
}
{
// timer be stopped, update the condition variable expired and wake main thread
std::lock_guard<std::mutex> locker(_mutex);
_expired = true;
_expired_cond.notify_one();
}
}).detach();
}
void startOnce(int delay, std::function<void()> task)
{
std::thread([delay, task]() {
std::this_thread::sleep_for(std::chrono::milliseconds(delay));
task();
}).detach();
}
void stop()
{
// do not stop again
if (_expired)
return;
if (_try_to_expire)
return;
// wait until timer
_try_to_expire = true; // change this bool value to make timer while loop stop
{
std::unique_lock<std::mutex> locker(_mutex);
_expired_cond.wait(locker, [this] {return _expired == true; });
// reset the timer
if (_expired == true)
_try_to_expire = false;
}
}
private:
std::atomic<bool> _expired; // timer stopped status
std::atomic<bool> _try_to_expire; // timer is in stop process
std::mutex _mutex;
std::condition_variable _expired_cond;
};
#endif // !_TIMER_H_
main.cpp
#include <iostream>
#include "timer.hpp"
void func1()
{
std::cout << "trigger func1" << std::endl;
}
void func2(int x)
{
std::cout << "trigger func2, x: " << x << std::endl;
}
int main(int argc, char* argv[])
{
Timer timer;
// execute task every timer interval
std::cout << "--- start period timer ----" << std::endl;
timer.start(1000, std::bind(func2, 3));
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
timer.stop();
std::cout << "--- stop period timer ----" << std::endl;
// execute task once after delay
std::cout << "--- start one shot timer ----" << std::endl;
timer.startOnce(1000, func1);
std::cout << "--- stop one shot timer ----" << std::endl;
getchar();
return 0;
}