ropieur
ropieur

Reputation: 130

asio::strand<asio::io_context::executor_type> vs io_context::strand

Since latest versions of boost, asio comes up with its new executors and provides with asio::strand<Executor>. So it is now perfectly possible to use asio::strand<asio::io_context::executor_type> instead of io_context::strand. But they cannot be used interchangeably.

Upvotes: 5

Views: 4313

Answers (1)

sehe
sehe

Reputation: 393769

io_context::strand is "legacy". I assumed it exists for interface compatibility with code that still uses boost::asio::io_service (also deprecated).

As the comments reflect I've since found out that io_context::strand is not actually deprecated, although I see no reason why this is the case, and close reading of the implementation leaves me with the conclusion that

  • asio::strand<Executor> is strictly better

  • mixing both strand services is not the best idea. In fact both services are documented with the same tag line:

     // Default service implementation for a strand.
    

    I can't help feeling there should be only one default :)

Modern strands don't reference an execution context, but wrap an executor.

While being technically different, it is conceptually the same.

The usage is the same for posting tasks:

post(s, task); // where s is either legacy or modern 
defer(s, task);
dispatch(s, task);

In fact you may have tasks with an associated executor, see:

You can no longer use the legacy strand to construct IO service objects (like tcp::socket or steady_timer). That's because the legacy strand cannot be type-erased into any_io_executor:

using tcp = boost::asio::ip::tcp;
boost::asio::io_context ioc;

auto modern = make_strand(ioc.get_executor());
tcp::socket sock(modern);

boost::asio::io_context::strand legacy(ioc);
tcp::socket sock(legacy); // COMPILE ERROR

If you really want you can force it by not using any_io_executor:

boost::asio::basic_stream_socket<tcp, decltype(legacy)> sock(legacy);
sock.connect({{}, 8989});

Upvotes: 4

Related Questions