In a thread which has not ever called and would never call asio::io_context.run(), must I invoke post() or dispatch() to dispatch tasks to the thread which has called asio::io_context.run()?
That's basically how that works. Yes, it's also a "cheap" way to implement a task queue (see e.g. stackoverflow.com/questions/…)
To the first part: yes. (You can replace "must" with "can")
Is it safe to directly call asio::async_write() or asio::async_read() in a thread which has not ever called and would never call asio::io_context.run() to dispatch tasks to the thread which has called asio::io_context.run()?
Yes (with caveats).
The caveats are that you're responsible for thread safety/synchronization. E.g. a tcp::socket object is not thread-safe. You should only call methods on it from one logical thread (e.g. strand) or critical section (e.g. using mutual exclusions, mutex).
The async initiators will work to get work onto the execution context (which .run()
s on any number of threads). From there it is highly idiomatic that all subsequent async initiation functions happen from completion handlers, so from these threads already.
Note that none of this is magical. In fact, all the async_ initiation functions know the executor
(associated with the IO object, usually) and this determines where the completion handler gets post
/dispatch
/defer
-ed to. In some cases you want to override this (e.g. using strand.wrap()
or the newer bind_executor()
function).
See also When must you pass io_context to boost::asio::spawn? (C++)