あめだまふぁくとりー

Boost.Graphとかできますん

boost::asio::asio_handler_is_continuation の効果

asio_handler_is_continuation の効果がいまいち良く分からなかったので調べてみました.

ある handler について, asio_handler_is_continuation の結果が true の場合, 処理が以下の様に少し変わります.

  • handler はスレッド固有の private queue に一度登録され, 後で全体の queue に登録される.
  • private queue から全体の queue に handler を移動した際, handler 待ちの他のスレッドを起こさない.

一つ目の結果により, handler を登録した関数が完了するまで, その handler が実行されることはありません (io_service::dispatch で登録した場合等は除きます).

二つ目の結果により, 登録した handler を同じスレッドで実行する確率が上昇します.

これらを以下は例で見てみます.

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

struct my_handler
{
    void operator()() const
    {
        std::cout << "my_handler: " << std::this_thread::get_id() << std::endl;
    }

    friend auto asio_handler_is_continuation(my_handler* h)
        -> bool
    {
        return h->is_continuation;
    }

    bool is_continuation;
};

int main(int argc, char* argv[])
{
    boost::asio::io_service io_service{};

    io_service.post([&]
    {
        // handler を登録して 1 秒間 sleep
        io_service.post(my_handler{argc != 1});
        std::this_thread::sleep_for(std::chrono::seconds{1});

        std::cout << "handler1: " << std::this_thread::get_id() << std::endl;
    });

    auto t1 = std::thread{[&]{
        io_service.run();
    }};

    auto t2 = std::thread{[&]{
        io_service.run();
    }};

    t2.join();
    t1.join();
}
  • asio_handler_is_continuation の結果が false の場合:
% ./a.out
my_handler: 0x10dd9c000
handler1: 0x10dd19000

my_handlerio_service::post で登録されると, 登録したスレッドは別のスレッドで即座に実行されています.

  • asio_handler_is_continuation の結果が true の場合:
% ./a.out continuation
handler1: 0x1040bc000
my_handler: 0x1040bc000

my_handler を登録した関数は 1 秒間 sleep しているにも関わらず, その関数が終了するまで my_handler は実行されていません.

また, my_handler は, それを登録したスレッドと同一のスレッドで呼び出されています.