定时器要求在固定的时间异步执行一个操作,比如boost库中的boost::asio::deadline_timer,以及MFC中的定时器。也可以利用c++11的thread, mutex, condition_variable 来实现一个定时器。

算法1(不推荐)

使用C++11中的thread, mutex, condition_variable来实现一个定时器。

注:此算法不推荐,因为每一个任务会创建一个线程。推荐用最下面第2种时间轮算法

#include

#include

#include

#include

#include

class Timer {

public:

Timer() :_expired(true), _try_to_expire(false) {}

Timer(const Timer& t) {

_expired = t._expired.load();

_try_to_expire = t._try_to_expire.load();

}

~Timer() {

Expire();

}

void StartTimer(int interval, std::function task) {

if (_expired == false) {

return;

}

_expired = false;

std::thread([this, interval, task]() {

while (!_try_to_expire) {

std::this_thread::sleep_for(std::chrono::milliseconds(interval));

task();

}

{

std::lock_guard locker(_mutex);

_expired = true;

_expired_cond.notify_one();

}

}).detach();

}

void Expire() {

if (_expired) {

return;

}

if (_try_to_expire) {

return;

}

_try_to_expire = true;

{

std::unique_lock locker(_mutex);

_expired_cond.wait(locker, [this] {return _expired == true; });

if (_expired == true) {

_try_to_expire = false;

}

}

}

private:

std::atomic _expired;

std::atomic _try_to_expire;

std::mutex _mutex;

std::condition_variable _expired_cond;

};

int main() {

Timer t;

t.StartTimer(1000, []() {std::cout << "Hello World!" << std::endl; });

std::this_thread::sleep_for(std::chrono::seconds(4));

t.Expire();

return 0;

}

算法2(推荐,时间轮)

使用时间轮算法:Linux内核就有这个算法。这里也有一个用户态的实现供参考:github.com/facebook/folly。它的高精度版本能实现微妙级别的定时。下面是一个简单的时间轮定时器的C++实现。原文的代码有问题,不能循环定时,经修改已经支持:

#include

#include

#include

#include

#include

#include

class TimerWheel {

public:

using Task = std::function;

explicit TimerWheel(size_t wheel_size, int interval_ms)

: wheel_size_(wheel_size),

interval_ms_(interval_ms),

wheel_(wheel_size),

current_index_(0) {}

~TimerWheel() {

Stop();

}

void Start() {

if (running_) {

return;

}

running_ = true;

thread_ = std::thread([this]() {

while (running_) {

std::this_thread::sleep_for(std::chrono::milliseconds(interval_ms_));

Tick();

}

std::cout << "timer oooops!" << std::endl;

});

thread_.detach();

}

void Stop() {

if (!running_) {

return;

}

running_ = false;

if (thread_.joinable()) {

thread_.join();

}

}

void AddTask(int timeout_ms, Task task) {

std::lock_guard lock(mutex_);

size_t ticks = timeout_ms / interval_ms_;

size_t index = (current_index_ + ticks) % wheel_size_;

size_t allindex = index;

for (size_t i = 1 ; allindex < wheel_size_; i++)

{

allindex = index * i;

if (allindex >= wheel_size_)

break;

wheel_[allindex].push_back(task);

}

}

private:

void Tick() {

std::lock_guard lock(mutex_);

auto& tasks = wheel_[current_index_];

for (const auto& task : tasks) {

task();

}

//tasks.clear();

current_index_ = (current_index_ + 1) % wheel_size_;

}

private:

size_t wheel_size_;

int interval_ms_;

std::vector> wheel_;

size_t current_index_;

bool running_ = false;

std::thread thread_;

std::mutex mutex_;

};

使用方法:

使用static声明以免被析构,可在cpp类外全局声明,第一个参数为任务容器最大数量,其下例中的10指最大10个任务,第二个参数为定时判断的毫秒数即最低检测时间单位,下例中的1000指轮子每1000毫秒检测一下有没有到期的任务,此数值越低延时越精确。

static TimerWheel timer(10, 1000);

在要使用的地方,启动并添加任务。例子中2000、3000为每2秒、每3秒执行一次任务。

timer.Start();

timer.AddTask(2000, []() {std::cout << "Task 1" << std::endl; });

timer.AddTask(3000, []() {std::cout << "Task 2" << std::endl; });

可以在需要的时候停止

timer.Stop();

原文链接:https://blog.csdn.net/sinat_28305511/article/details/131495316