ASIO proper handling of multiple threads + strand + socket + timer
Asked Answered
S

1

7

I'm using the latest ASIO version(as of this time 1.18.0). Currently designing a multithreaded asynchronous TCP server with timers(for timeouts). I have a single io_context with multiple threads calling its run() function. I accept new connections like this:

void Server::AcceptConnection()
{
    acceptor_.async_accept(asio::make_strand(io_context_),
            [this](const asio::error_code& error, asio::ip::tcp::socket peer) {
                if (!error) {
                    std::make_shared<Session>(std::move(peer))->run();
                }
                AcceptConnection();
            });
}

And here a stripped down version of the Session class:

class Session : public std::enable_shared_from_this<Session>
{
public:
    Session(asio::ip::tcp::socket&& peer) : peer_(std::move(peer)) {}
    void run()
    {
        /*
        asio::async_read(peer_, some_buffers_, some_callback_);
        timeout_timer_.expires_after();
        timeout_timer_.async_wait();
        // etc
        */
    }
    
private:
    asio::ip::tcp::socket peer_;
    asio::steady_timer timeout_timer_{peer_.get_executor()};
}

Please note the initialization of the timer. Also, beware that I'm not using any kind of strand::wrap() or asio::bind_executor() wrappers for the async handlers of the socket and the timer, because of what I understood, they are no longer required if I initialize my objects with the proper executors.

The question here is: Is that a correct way of handling TCP connection inside a strand with a timer inside the same strand that the TCP connection is using?

Note: The timer is used to abort the TCP connection if the timeout passes.

Sequester answered 23/9, 2020 at 14:29 Comment(1)
If ever there was a question that deserved an upvote, it's this one. It's hard to understand why this simple technique isn't in the examples, but if it's there, I sure can't find it.Flibbertigibbet
O
7

Yes, this is the way I write the things as well, using the new interfaces.

I remember having the same concerns when I started out using the new interface, and ended up checking that the various completion handlers do run on the expected strand, which they do.

All in all, these result in significant simplifications in library usage.

Oslo answered 23/9, 2020 at 21:30 Comment(3)
This does indeed eliminate just a mountain of complexity from the usage. Strange that it's not better documented, really.Flibbertigibbet
@AllanBazinet The only way to "better" document is by detailing how it was (not uniform) and how it has become as a change. That's bound to generate more confusion. IMO the "design/why" sections of the documentation are very under-appreciated (e.g. here) and there is of course the changelog. I do think that some better "news feed" is very welcome.Oslo
thanks for clarifing it. I think that how-to examples are missing in the documentation. In particular, before-after examples. Smashing my head to get the new idea... mostly done, thanks to you both too :)Shilashilha

© 2022 - 2024 — McMap. All rights reserved.