定时器
大约 2 分钟cpp
异步定时器
异步定时器头文件 MyTimer.h
#pragma once
#pragma once
#include <iostream>
#include <mutex>
#include <thread>
#include <functional>
#include <condition_variable>
#include <atomic>
using namespace std;
class MyTimer {
private:
condition_variable cv;
mutex mut;//与cv配合
atomic<bool> expired; //timer stop status
atomic<bool> tryToExpire;//timer is in stop process.
public:
MyTimer();
//interval: ms
void start(int interval, std::function<void()> task);
void stop();
};
头文件 MyTimer.h 的实现源码
#pragma once
#include <iostream>
#include <mutex>
#include <thread>
#include <functional>
#include <condition_variable>
#include <atomic>
#include "MyTimer.h"
using namespace std;
condition_variable cv;
mutex mut;//与cv配合
atomic<bool> expired; //timer stop status
atomic<bool> tryToExpire;//timer is in stop process.
MyTimer::MyTimer() {
expired = true;
tryToExpire = false;
}
//interval: ms
void MyTimer::start(int interval, std::function<void()> task)
{
if (expired == false)//has already started, do not start again
return;
// start async timer, launch thread and wait in that thread
expired = false;
//将lambda函数传递给线程,做线程函数
std::thread([this, interval, task]() {
//小缺点:在task执行的过程中设置tryToExpire为true的话,需要等到本次task执行完毕后才能被while条件判断检测到。
while (!tryToExpire)
{
// sleep every interval and do the task again and again until times up
std::this_thread::sleep_for(std::chrono::milliseconds(interval));
task(); //call this function every interval milliseconds.
}
// timer be stopped, update the condition variable expired and wake main thread
std::lock_guard<std::mutex> locker(mut);
expired = true;
cv.notify_one();
}).detach();
}
void MyTimer::stop()//该接口负责修改tryToExipired的值。
{
// do not stop again
if (expired)
return;
if (tryToExpire)
return;
// wait until timer
tryToExpire = true; // change this bool value to make timer while loop stop. This val is atomic type.
std::unique_lock<std::mutex> locker(mut);
cv.wait(locker, [this] {return expired == true; });//不给lambda函数串this,不能使用成员变量expired!
// reset the timer,
//成功停止后,设置tryToExpire为false. 其实,可以不使用wait动作,将tryToExpire=false的动作放到
//start函数,当while循环被打断后,立即设置tryToExpire为false。
//但是,这样单独放在这里设置也有好处吧,实现了tryToExipired的值仅仅由该stop函数负责。例如,任务线程成功结束后,这里可以进行一些额外的善后动作,
if (expired == true)
tryToExpire = false;
}
使用案例 TestTimer.cpp,需要注意的是在 main 函数通过 start 启动异步定时器后由于 getchar() 阻塞了控制台(要求用户输入字符并回车),导致看上去控制台一直在打印数字(定时任务一直在执行)好像没有实现异步任务,此时只要在控制台中输入任意字符并回车,即会继续向下执行并关闭定时任务。
// CustomTimer.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include "MyTimer.h"
using namespace std;
void printNum() {
static int a = 0;
a++;
cout << "a=" << a << endl;
}
int main()
{
MyTimer obj;
obj.start(1000, printNum);
/*
* 定时线程执行了detatch,这里需要等待才能看到起输出数字到屏幕上
* getchar()阻塞主线程执行,控制台中输入任意字符后回车向下执行
* 关闭定时任务
*/
getchar();
obj.stop();
getchar();
return 0;
}
