当前位置:   article > 正文

C++ 实现定时器的两种方法(线程定时和时间轮算法修改版)_c++ 定时器

c++ 定时器

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

1、使用C++11中的thread, mutex, condition_variable来实现一个定时器。
注:此算法会每一个任务创建一个线程,不推荐。推荐用最下面第2种时间轮算法

#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>
#include <condition_variable>

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<void()> 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<std::mutex> 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<std::mutex> locker(_mutex);
            _expired_cond.wait(locker, [this] {return _expired == true; });
            if (_expired == true) {
                _try_to_expire = false;
            }
        }
    }

private:
    std::atomic<bool> _expired;
    std::atomic<bool> _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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

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


#include <chrono>
#include <functional>
#include <list>
#include <mutex>
#include <thread>
#include <vector>

class TimerWheel {
public:
    using Task = std::function<void()>;

    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<std::mutex> 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<std::mutex> 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<std::list<Task>> wheel_;
    size_t current_index_;
    bool running_ = false;
    std::thread thread_;
    std::mutex mutex_;
};



  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85

使用方法:
使用static声明以免被析构,可在cpp类外全局声明,第一个参数为任务容器最大数量,第二个参数为定时判断的毫秒数即最低检测时间单位

static TimerWheel timer(10, 1000);
  • 1

在要使用的地方,启动并添加任务

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

可以在需要的时候停止

timer.Stop();
  • 1

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/599468
推荐阅读
相关标签
  

闽ICP备14008679号