読者です 読者をやめる 読者になる 読者になる

Boost.Asio タイマーのキャンセル

C++

Boost.Asioのdeadline_timerには、Boost 1.47.0からcancel_one()というメンバ関数が追加されます。
元からcancel()というのはあるので、その違いをここで紹介します。


cancel()は、async_waitしてる全てのハンドラをキャンセルします。
戻り値として、キャンセルした個数が返されます。ここでは2。

#include <iostream>
#include <string>
#include <ctime>
#include <boost/asio.hpp>
#include <boost/format.hpp>
#include <boost/current_function.hpp>

namespace asio = boost::asio;

std::string now()
{
    std::time_t t;
    std::time(&t);
    std::tm* st = std::localtime(&t);

    return (boost::format(" %1%/%2%/%3% %4%:%5%:%6% : ")
                % (1900 + st->tm_year)
                % (1 + st->tm_mon)
                % st->tm_mday
                % st->tm_hour
                % st->tm_min
                % st->tm_sec
            ).str();
}

void on_timer1(const boost::system::error_code& error)
{
    if (error == asio::error::operation_aborted)
        std::cout << BOOST_CURRENT_FUNCTION << now() << "cancelled" << std::endl;
    else if (error)
        std::cout << BOOST_CURRENT_FUNCTION << now() << "other error" << std::endl;
    else
        std::cout << BOOST_CURRENT_FUNCTION << now() << "correct" << std::endl;
}

void on_timer2(const boost::system::error_code& error)
{
    if (error == asio::error::operation_aborted)
        std::cout << BOOST_CURRENT_FUNCTION << now() << "cancelled" << std::endl;
    else if (error)
        std::cout << BOOST_CURRENT_FUNCTION << now() << "other error" << std::endl;
    else
        std::cout << BOOST_CURRENT_FUNCTION << now() << "correct" << std::endl;
}

int main()
{
    asio::io_service io_service;
   
    asio::deadline_timer timer(io_service);
    std::cout << now() << "start" << std::endl;

    timer.expires_from_now(boost::posix_time::seconds(2));
    timer.async_wait(on_timer1);
    timer.async_wait(on_timer2);

    const int count = timer.cancel();
    std::cout << "cancel count : " << count << std::endl;
   
    io_service.run();
}
 2011/6/29 10:27:3 : start
cancel count : 2
void __cdecl on_timer1(const class boost::system::error_code &) 2011/6/29 10:27:3 : cancelled
void __cdecl on_timer2(const class boost::system::error_code &) 2011/6/29 10:27:3 : cancelled

キャンセルされたハンドラは呼ばれなくなるのではなく、即ハンドラが呼ばれ、error_codeとしてasio::error::operation_abortedが渡されます。


cancel_one()は、タイマーのハンドラキューから先頭ひとつをキャンセルします。

#include <iostream>
#include <string>
#include <ctime>
#include <boost/asio.hpp>
#include <boost/format.hpp>
#include <boost/current_function.hpp>

namespace asio = boost::asio;

std::string now()
{
    std::time_t t;
    std::time(&t);
    std::tm* st = std::localtime(&t);

    return (boost::format(" %1%/%2%/%3% %4%:%5%:%6% : ")
                % (1900 + st->tm_year)
                % (1 + st->tm_mon)
                % st->tm_mday
                % st->tm_hour
                % st->tm_min
                % st->tm_sec
            ).str();
}

void on_timer1(const boost::system::error_code& error)
{
    if (error == asio::error::operation_aborted)
        std::cout << BOOST_CURRENT_FUNCTION << now() << "cancelled" << std::endl;
    else if (error)
        std::cout << BOOST_CURRENT_FUNCTION << now() << "other error" << std::endl;
    else
        std::cout << BOOST_CURRENT_FUNCTION << now() << "correct" << std::endl;
}

void on_timer2(const boost::system::error_code& error)
{
    if (error == asio::error::operation_aborted)
        std::cout << BOOST_CURRENT_FUNCTION << now() << "cancelled" << std::endl;
    else if (error)
        std::cout << BOOST_CURRENT_FUNCTION << now() << "other error" << std::endl;
    else
        std::cout << BOOST_CURRENT_FUNCTION << now() << "correct" << std::endl;
}

int main()
{
    asio::io_service io_service;
   
    asio::deadline_timer timer(io_service);
    std::cout << now() << "start" << std::endl;

    timer.expires_from_now(boost::posix_time::seconds(2));
    timer.async_wait(on_timer1);
    timer.async_wait(on_timer2);

    timer.cancel_one();
   
    io_service.run();
}
 2011/6/29 10:32:0 : start
void __cdecl on_timer1(const class boost::system::error_code &) 2011/6/29 10:32:0 : cancelled
void __cdecl on_timer2(const class boost::system::error_code &) 2011/6/29 10:32:2 : correct