c++ 11实现一个定时器,周期性地执行指定的task

可以直接使用c++11的thread, mutex, conditon_variable来实现, 结合了std::function.

Note:

1)start函数,开辟一个新的线程,并detach,在这个线程中周期性地执行task。

建立一个std::thread线程时,需要传入一个可调用对象,这里使用了lambda函数,非常方便。
start函数的入参是,周期时间ms,以及一个std::function

2) 使用了c++11的原子变量automic,比较方便。

3)stop函数的作用是给已经正在运行的任务线程发一个通知(通过改变一个bool成员变量),然后使用一个conditon_variable进入等待状态。

任务线程会在每次执行新一轮的任务时检查该变量的值,并判断是否停止, 停止后,会使用condition_variable通知stop函数不用等待了。

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
#pragma once
#include <iostream>
#include <mutex>
#include <thread>
#include <functional>
#include <condition_variable>
#include <atomic>

using namespace std;
class MyTimer {
   
public:
    MyTimer() {
        expired = true;
        tryToExpire = false;
    }

    //interval: ms
    void 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 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;

    }

private:
    condition_variable cv;
    mutex mut;//与cv配合

    atomic<bool> expired; //timer stop status
    atomic<bool> tryToExpire;//timer is in stop process.

 };

Test:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void printNum() {
    static int a = 0;
    a++;
    cout << "a=" << a << endl;
}
void main() {

    MyTimer obj;
    obj.start(1000,printNum);

    getchar();//定时线程执行了detatch,这里需要等待才能看到起输出数字到屏幕上
    obj.stop();
    getchar();
    return;
}

Ref:

https://blog.csdn.net/u012234115/article/details/89857431

https://www.cnblogs.com/grandyang/p/4340948.html