Немного поиграв, получается, что asio_handler_is_continuation
не считается устаревшим; и нет способа заменить его на defer
в настоящее время.
Чтобы перенаправить любые post
вызовы на defer
, я предоставил следующего пользовательского исполнителя:
template<typename UnderlyingExecutor, typename std::enable_if<boost::asio::is_executor<UnderlyingExecutor>::value, int>::type = 0>
class continuation_executor
{
private:
UnderlyingExecutor _ex;
public:
continuation_executor(UnderlyingExecutor ex)
:_ex(ex){}
template<class Function, class Allocator>
void post(Function f, Allocator a)
{
std::cout<<"Redirected to defer()"<<std::endl;
_ex.defer(BOOST_ASIO_MOVE_CAST(Function)(f),a);
}
template<class Function, class Allocator>
void defer(Function f, Allocator a)
{
std::cout<<"defer() called"<<std::endl;
_ex.defer(BOOST_ASIO_MOVE_CAST(Function)(f),a);
}
template<class Function, class Allocator>
void dispatch(Function f, Allocator a)
{
std::cout<<"dispatch() called"<<std::endl;
_ex.dispatch(BOOST_ASIO_MOVE_CAST(Function)(f),a);
}
auto context() -> decltype(_ex.context())
{
return _ex.context();
}
void on_work_started()
{
_ex.on_work_started();
}
void on_work_finished()
{
_ex.on_work_finished();
}
};
Это действительно тривиальный исполнитель, полностью полагающийся на базового исполнителя, с continuation_executor::post
, который перенаправляет на базового исполнителя defer
.
Но когда я передаю обработчик в async_read_some
с чем-то вроде bind_executor(conti_exec, handler)
, я получаю следующий вывод:
dispatch() called
Таким образом, переданный обработчик не назначается через post()
; это запланировано другими способами. Конкретно, встроенная асинхронная функция, такая как asio::async_read_some
, планирует внутренний объект операции с помощью scheduler::post_immediate_completion
, затем io_context::run
выполняет операцию.
По завершении асинхронной операции вызывается метод complete
объекта операции для выполнения предоставленного пользователем обработчика. Этот метод complete
, по крайней мере в текущей реализации, использует связанный метод исполнителя dispatch
для запуска обработчика. Там нет места для выше крюка. Так что это совершенно мрачно; попытка использовать defer
вместо asio_handler_is_continuation
не удалась.
То, что я сказал в своем вопросе: «Начиная с Boost 1.66, приведенный выше код, скорее всего, не окажет никакого влияния (без макроса BOOST_ASIO_NO_DEPRECATION).», Совершенно неверно. asio_handler_is_continuation
все еще действует, и не устарело с 1.67 .
Это свидетельство того, что asio_handler_is_continuation
все еще действует:
// Start an asynchronous send. The data being sent must be valid for the
// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
void async_send(base_implementation_type& impl,
const ConstBufferSequence& buffers,
socket_base::message_flags flags, Handler& handler)
{
bool is_continuation =
boost_asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef reactive_socket_send_op<ConstBufferSequence, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler);
BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
&impl, impl.socket_, "async_send"));
start_op(impl, reactor::write_op, p.p, is_continuation, true,
((impl.state_ & socket_ops::stream_oriented)
&& buffer_sequence_adapter<boost::asio::const_buffer,
ConstBufferSequence>::all_empty(buffers)));
p.v = p.p = 0;
}
Обратите внимание, что он использует boost_asio_handler_cont_helpers
, чтобы узнать, является ли обработчик продолжением. boost_asio_handler_cont_helpers
внутренне вызывает asio_handler_is_continuation
.
async_send
используется async_write_some
для внутренних целей. Я не проверял все встроенные асинхронные задачи, которые предоставляет библиотека asio, но я почти уверен, что другие асинхронные задачи выполняют свой обработчик таким же образом.
Итак, если вы хотите, чтобы встроенные асинхронные задачи выполняли ваш обработчик как продолжение, вам придется положиться на asio_handler_is_continuation
. defer
не собирается полностью заменить его! defer
можно использовать только тогда, когда вы планируете обработчик непосредственно из вашего кода.