天天看點

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;
}      

運作:

BOOST 定時器 stop探究

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;
}      
BOOST 定時器 stop探究

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的定時器吧!

.

/************* 社會的有色眼光是:博士生、研究所學生、大學生、工廠中的房間勞工; 重點大學高材生、普通院校、二流院校、野雞大學; 年薪百萬、五十萬、五萬; 這些都隻是帽子,可以失敗千百次,但我和社會都覺得,人隻要成功一次,就能換一頂帽子,隻是社會看不見你之前的失敗的帽子。 當然,換帽子決不是最終目的,走好自己的路就行。 杭州.大話西遊 *******/

繼續閱讀