• C++ Timer


    Timer机制

    这里所说的Timer机制是定时器(Timer),例如在Javascript中就提供定时执行代码的功能。但是在C++标准中暂时没有实现这一功能的函数。

    Javascript中的Timer

    Javascript用来处理延时和定时任务的setTimeOut和setInterval函数应用非常广泛,它们都用来处理延时和定时任务,比如打开网页一段时间后弹出一个登录框,页面每隔一段时间发送异步请求获取最新数据等等。但它们的应用是有区别的。

    setTimeout

    setTimeout函数用来指定某个函数或某段代码,在多少毫秒之后执行。它返回一个整数,表示定时器的编号,以后可以用clearInterval来取消这个定时器。setTimeout只执行一次。

    var timeId=setTimeout(func|code,delay)    //间隔delay毫秒执行函数func或者code
    

    比如下面这段代码:

    console.log('First');
    setTimeout('console.log('Second')',1000);
    console.log('Third');
    

    的执行结果是先打印出"First与Third",然后再1000ms之后打印出"Second"。

    而在传入函数的时候,我们还可以增加参数:

    setTimeout(function(a,b,c){console.log(a+b);console.log(c);},1000,1,1,5);
    

    此外,如果被setTimeout推迟执行的回调函数是某个对象的方法,那么用到的this关键字将指向全局环境:

    var x = 1;var o = {x: 2,y: function(){console.log(this.x);}};setTimeout(o.y,1000);
    

    执行结果x的值为1而不是定义的对象o中的2!

    给出一个实际中使用的小例子:

    function User(login) {
        this.login = login;
        this.sayHi = function() 
        {console.log("Hello "+this.login);}
    }
    var user = new User('John');
    setTimeout(function() {user.sayHi();}, 1000);
    

    setTimeout这里调用的为function(){user.sayHi()};,因为如果执行user.sayHi,他会再全局对象中执行,this.login取不到值。

    setInterval

    setInterval函数的用法与setTimeout完全一致,区别仅仅在于setInterval指定某个任务每隔一段时间就执行一次,也就是无限次的定时执行。对应的取消函数为clearInterval

    运行机制

    setTimeout和setInterval的运行机制是,将指定的代码移出本次执行,等到下一轮Event Loop时,再检查是否到了指定时间。如果到了,就执行对应的代码;如果不到,就等到再下一轮Event Loop时重新判断。这意味着,setTimeout指定的代码,必须等到本次执行的所有代码都执行完,才会执行。
    每一轮Event Loop时,都会将“任务队列”中需要执行的任务,一次执行完。setTimeout和setInterval都是把任务添加到“任务队列”的尾部。因此,它们实际上要等到当前脚本的所有同步任务执行完,然后再等到本次Event Loop的“任务队列”的所有任务执行完,才会开始执行。由于前面的任务到底需要多少时间执行完,是不确定的,所以没有办法保证,setTimeout和setInterval指定的任务,一定会按照预定时间执行。
    比如说我用了setTimeout延迟了一个函数1000ms后执行,但是我代码后面存在耗时超过1000ms的执行代码,那么我利用setTimeout延迟的函数必须等到耗时很长的代码执行完成后才能轮到它执行。这一点会造成一种"累积触发"的现象,假如是使用setInterval,存在上述耗时很长的代码,那么setInterval的函数会排队并逐渐被累积起来,等到前面的代码执行完成会一股脑的连续触发。

    C++ Timer

    一个非常简单的库

    这个是由shalithasuranga写的非常简易的timer
    我们将代码贴在下面:

    main.cpp:

    #include <iostream>
    #include "timercpp.h"
    
    using namespace std;
    
    int main() {
        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); 
    
        cout << "I am Timer" <<endl;
        while(true); // Keep mail thread active
    }
    

    timercpp.h:

    #include <iostream>
    #include <thread>
    #include <chrono>
    
    class Timer {
        bool clear = false;
    
        public:
            void setTimeout(auto function, int delay);
            void setInterval(auto function, int interval);
            void stop();
    
    };
    
    void Timer::setTimeout(auto 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();
    }
    
    void Timer::setInterval(auto 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;
    }
    

    首先看一下main函数,调用了两个接口setTimeout与setInterval函数,两个函数是lambda表达式(捕捉引用符号)。其实就是一个简单的测试接口函数。

    下面再谈一谈Timer的接口,首先auto的写法适用于C++20,为了符合众多编译器,我们可以改成模板形式:

    #include <iostream>
    #include <thread>
    #include <chrono>
    
    class Timer {
    	bool clear = false;
    
    public:
    	template<typename T>
    	void setTimeout(T function, int delay);
    	template<typename T>
    	void setInterval(T function, int interval);
    	void stop();
    
    };
    
    template<typename T>
    void Timer::setTimeout(T 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 T>
    void Timer::setInterval(T 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;
    }
    

    在Timer类中定义了一个clear变量,是用来表示计时器是否应该停止的变量。然后出现了std::thread t([=]),这个lambda函数用来判断计时器是否应该停止,如果停止了就立刻返回。然后调用了std::this_thread::sleep_for用来休眠线程,可以参看这个.功能为阻塞当前线程执行,至少经过指定的 sleep_duration 。此函数可能阻塞长于 sleep_duration ,因为调度或资源争议延迟。

    我们分离:t.detach(),从 thread 对象分离执行的线程,允许执行独立地持续。一旦线程退出,则释放所有分配的资源。

    Boost Asio

    再有就是Boost库了,但是这个库过于庞大,有兴趣的可以去看一看:Boost Asio

  • 相关阅读:
    js实现金额千分位显示
    iview中select组件使用总结
    在VUE中使用QRCode.js
    vue echart使用总结
    Iview Table组件中各种组件扩展
    前端架构模式Mvc和Mvvm
    express 中间件
    http与https的区别
    前后端分离与不分离的区别,两者的优势
    TCP三次握手、四次挥手
  • 原文地址:https://www.cnblogs.com/yunlambert/p/10226468.html
Copyright © 2020-2023  润新知