BOOST 定时器 stop探究

 

Asio是一个建立在Boost所提供的相关组件之上的异步的网络库,可以运行在Win/Linux/Unix等各种平台之上。

不过随着C++11的发布,其对Boost的依赖也越来越少,作者又做了一个不依赖于Boost的版本。

1.  同步Timer:  调用wait后立即阻塞

#include <iostream>
#include <boost/asio.hpp>

int main()
{
boost::asio::io_service io;
boost::asio::deadline_timer timer(io, boost::posix_time::seconds(5));

timer.wait();

std::cout << "Hello, world!" << std::endl;

return 0;
}

实测效果,程序开始运行后3秒,打印了:Hello, world!

 

2.  异步Timer: wait后不立即阻塞,调用io的run方法时才会阻塞

#include <iostream>
#include <boost/asio.hpp>
#include <boost/thread.hpp>

void print(const boost::system::error_code& err)
{
   std::cout << "Hello, world! " << std::endl;
}

int main()
{
    boost::asio::io_service io;
    boost::asio::deadline_timer timer(io, boost::posix_time::seconds(5));

    std::cout << "----gointo 0---- " << std::endl;

    timer.async_wait(&print);
    //timer.cancel();  取消定时器, 这样后续io.run方法将不会阻塞,但是定时器回调函数会立马被执行

    std::cout << "----gointo 1---- " << std::endl;

    io.run();
    std::cout << "----gointo 2-!--- " << std::endl;

    return 0;
}

运行:

2.1

如果让上图内的timer.cancel()这句代码工作,那么效果将是:

取消定时器后, 定时器回调函数会立马被执行,同时后续io.run方法将不会阻塞 

2.2

如果我们希望在开启定时器后,本线程内的代码流仍能继续向下走,

我们只有改一改代码了:将开启定时器的代码封装在一个新的线程内,这样阻塞的就不是本线程,而是新开的线程了。

如下面的例子3所示。

3  异步Timer:  将开启定时器的代码封装在一个新的线程内,这样阻塞的就不是本线程,而是新开的线程了。

#include <iostream>
#include <boost/asio.hpp>
#include <boost/thread.hpp>

void print(const boost::system::error_code& err)
{
   std::cout << "Hello, world! " << std::endl;
}

void func_timer_test()
{
   boost::asio::io_service io;
   boost::asio::deadline_timer timer(io, boost::posix_time::seconds(5));

   std::cout << "----gointo 0---- " << std::endl;
   timer.async_wait(&print);
   std::cout << "----gointo 1---- " << std::endl;

   io.run();
   std::cout << "----gointo 2---- " << std::endl;
}
 
int main()
{
    boost::thread thread_timer_test(func_timer_test);
    thread_timer_test.detach();

    while(1){
       std::cout << "----main loop()--- " << std::endl;
       boost::this_thread::sleep(boost::posix_time::seconds(1));
    }

    return 0;
}

运行:

 

4  异步Timer:  取消定时器,因为取消定时器后,事先设置的定时器回调函数会被立马执行,所以必须在定时器回调函数内通过当前的错误码来进行判断。

#include <iostream>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/exception/all.hpp>
#include <boost/system/error_code.hpp>
#include <boost/asio.hpp>
#include <string>

void print(const boost::system::error_code& err)
{
   if(err){
      std::cout << err.category().name() << std::endl;
      std::cout << err.value() << std::endl;
   }
   
   std::cout << "Hello, world! " << std::endl;
}

int main()
{
    boost::asio::io_service io;
    boost::asio::deadline_timer timer(io, boost::posix_time::seconds(5));

    std::cout << "----gointo 0---- " << std::endl;

    timer.async_wait(&print);
    timer.cancel();

    std::cout << "----gointo 1-*--- " << std::endl;

    io.run();

    std::cout << "----gointo 2-$--- " << std::endl;

    return 0;
}

4.1

如果屏蔽上图代码内的timer.cancel()这句,即不取消定时器时,

运行结果如下图:

存在5秒的定时。 

4.2

取消定时器,即上图代码的运行结果:

代码立即执行完毕,且定时器回调内判断出,发生了异常。

那么,我们平常在使用boost库定时器的时候,如果我们希望真正取消一个事先已经设置好的定时器回调函数的执行,

我们可以换种思路:在定时器回调函数内做if-else判断,如果被取消了干啥(一般是空处理),定时结束正常进入时干啥,区分开处理就好了。

 

后记:

对于取消定时器任务,如果我在主线程内调用timer.cancel来取消定时器线程内的定时器任务,实测运行会段错误。

也即是说,本博客最终还是没能搞定单次定时器任务的取消。

百度了不少博客,都没能搞定定时器任务的取消。

需要重要说明的是:我所谓的取消定时器任务的严格定义是,我开了一个定时器任务,但是这个任务由于时间未到所以还没有被执行到,我中途希望取消该定时器任务。

https://blog.csdn.net/zhongjiezheng/article/details/44343959

这篇博客的访问量竟然还挺高的,但是他实现的是一个周期性定时器,他所谓的停止指的仅仅是取消这个定时器任务的周期性执行而已。和我所需要的取消定时器任务的需求完全是两码事。

我们来验证上面博客的代码是无法完成取消定时器任务的,复制其代码,简单修改了下,贴代码:

#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <iostream>

class MyTimer
{
public:
    template<typename F>
    MyTimer(boost::asio::io_service& ios, F func, int interval, bool start = true) :
        m_func(func),
        m_interval(interval),
        m_timer(ios, boost::posix_time::millisec(interval)), 
        m_flag(start)
    {
        m_timer.async_wait(boost::bind(&MyTimer::call_func, this, boost::asio::placeholders::error));
    }
    void call_func(const boost::system::error_code&)
    {
        if (!m_flag)
        {
        std::cout << "cancel!" << std::endl;
            return;
        }
        m_func();
        //m_timer.expires_at(m_timer.expires_at() + boost::posix_time::millisec(m_interval));
        //m_timer.async_wait(boost::bind(&MyTimer::call_func, this, boost::asio::placeholders::error));
    }
    void stop()
    {
        m_flag = false;
    }
    void start(int new_interval)
    {
        m_flag = true;
        m_interval = new_interval;
        m_timer.expires_from_now(boost::posix_time::millisec(m_interval));
        m_timer.async_wait(boost::bind(&MyTimer::call_func, this, boost::asio::placeholders::error));
    }
private:
    boost::function<void()> m_func;
    int m_interval;
    boost::asio::deadline_timer m_timer;
    bool m_flag;
};

void print1()
{
    std::cout << "11111" << std::endl;
}

void print2()
{
    std::cout << "22222" << std::endl;
}

boost::asio::io_service ios;
MyTimer at1(ios, print1, 15000); // 希望该定时器任务15秒后被执行,中途我们来取消之
//MyTimer at2(ios, print2, 8000);

void threadfun()
{
    boost::this_thread::sleep(boost::posix_time::milliseconds(2000));
    at1.stop();
    
    //at2.start(1000);
    
    //at1.stop();
    //at2.stop();
}

int main()
{
    // boost::this_thread::sleep(boost::posix_time::milliseconds(5000));
    boost::thread_group thr_grp;
    thr_grp.create_thread(boost::bind(threadfun));
    ios.run();
    getchar();
    return 0;
}

// 实验失败  定时器任务没有被取消。 

运行:

实验失败 定时器任务没有被取消。

 

好吧,折腾得够久了,无比的烦躁。 我还是自己基于linux去封装一个CPP的定时器吧!

 

 

.

.

posted @ 2020-10-24 23:53  一匹夫  阅读(869)  评论(0编辑  收藏  举报