Среди заголовочных файлов "asio samples" лежит "скромный" ma/strand_wrapped_handler.hpp. Когда-то, разбираясь с invocation strategy и io_service::strand, я наткнулся на то, что стандартно обернутый через asio::io_service::strand::wrap() функциональный объект делает проверку (на исполнение в контексте strand-а) и в asio_handler_invoke, и в своем operator(). Так вот, обычно достаточно делать такую проверку только в asio_handler_invoke. "Обычно" в этом предложении означает: для всех классов Boost.Asio и вообще везде, где вы сами не вызываете напрямую operator() у функционального объекта, "обернутого" через strand. В противном случае, при использовании asio_handler_invoke с таким образом обернутым функциональным объектом (вспоминаем, что Boost.Asio всегда вызывает все user-defined обработчики только так), проверка на исполнение в контексте strand будет выполняться дважды! Данная операция не такая уж и легкая (использует мютексы/критические секции). Кому интересно, загляните в исходники Asio.
С тех пор (давно) вместо asio::io_service::strand::wrap() везде в "asio samples" я использую свой макрос MA_STRAND_WRAP(strand, handler), определенный в том самом ma/strand_wrapped_handler.hpp. Моя strand-"обертка" для функционального объекта использует asio::io_service::strand::dispatch только в asio_handler_invoke.
Автору Asio я писал (давно, в список рассылки). Он ответил, что те, кого волнуют подобные двойные проверки (я согласен с тем, что еще не известно, как/насколько они скажутся на производительности) смогут аналогично мне сами написать свою обертку. Кхм... В свете того, что Asio все чаще используется даже высоконагруженными гигантами вроде Mail.ru (и, кажется, уже давно в Yandex), хотел бы порекомендовать пользователям Asio по-чаще смотреть в исходники самой библиотеки Asio.
1 комментарий:
Вместо макроса я перешел на собственную (надеюсь, что легкую) обертку вокруг boost::asio::io_service::strand - ma::strand. См. файл "ma/strand.hpp".
Отправить комментарий