js 的setTimer和setInterval非常好用,于是想到在c++实现一个类似语法简洁的定时器。
github上已有实现timercpp
其使用方式如下:
Timer t = Timer();
t.setInterval([&]() {
cout << "Hey.. After each 1s..." << endl;
}, 1000);
t.setTimeout([&]() {
cout << "Hey.. After 5.2s. But I will stop the timer!" << endl;
t.stop();
}, 5200);
非常简洁。可惜项目使用了auto关键字不能用在c++11 的版本上,于是考虑做一些更改,想到我们可以使用模板来实现类似的功能。
完整的实现如下:
(使用方法和上面例子一样)
#include <iostream>
#include <thread>
#include <chrono>
class Timer {
bool clear = false;
public:
template<typename Function>
void setTimeout(Function function, int delay);
template<typename Function>
void setInterval(Function function, int interval);
void stop();
};
template<typename Function>
void Timer::setTimeout(Function function, int delay) {
this->clear = false;
std::thread t([=]() {
if(this->clear) return;
std::this_thread::sleep_for(std::chrono::milliseconds(delay));
if(this->clear) return;
function();
});
t.detach();
}
template<typename Function>
void Timer::setInterval(Function function, int interval) {
this->clear = false;
std::thread t([=]() {
while(true) {
if(this->clear) return;
std::this_thread::sleep_for(std::chrono::milliseconds(interval));
if(this->clear) return;
function();
}
});
t.detach();
}
void Timer::stop() {
this->clear = true;
}
分析:
接下来我们尝试分析一下原理:
在 setTimeout中,第一行设置用于控制计时器处于活动状态还是非活动状态的标志,以将其设置为活动状态( 不清除该定时器 ):
this->clear = false;
接下来实例化一个新的线程对象,参数是lambda函数,[=]()
是指用到的外部元素全部按值操作。
std::thread t([=]() {
该(lambda)函数首先检查timer是否仍处于活动状态(否则它将立即返回),因为它可能已被另一个函数停止。如果处于活动状态,它将等待,sleep_for 会阻塞线程指定的时间:
if(this->clear) return;
std::this_thread::sleep_for(std::chrono::milliseconds(delay));
然后,我们再次检查计时器是否仍处于活动状态,如果是,则调用传递给setTimeout的函数:
if(this->clear) return;
function();
但是这个线程对象的寿命很短:它将在setTimeout函数结束时被销毁。而且我们希望真实线程的寿命超过线程对象的寿命。当thread::detach()函数被调用后,执行的线程从线程对象中被分离,已不再被一个线程对象所表达--这是两个独立的事情。C++线程对象可以被销毁,同时OS执行的线程可以继续。如果程序想要知道执行的线程何时结束,就需要一些其它的机制。
网友评论