Daszek
Daszek

Reputation: 177

async_connect() timeout with multiple threads performing io_service.run()

I am trying to implement async_connect() with a timeout.

    async_connect_with_timeout(socket_type & s,
        std::function<void(BoostAndCustomError const & error)> const & connect_handler,
        time_type timeout);

When operation completes connect_handler(error) is called with error indicating operation result (including timeout).

I was hoping to use code from timeouts example 1.51. The biggest difference is that I am using multiple worker threads performing io_service.run().

What changes are necessary to keep the example code working?

My issues are:

  1. When calling :

    Start() {
        socket_.async_connect(Handleconnect);
        dealine_.async_wait(HandleTimeout);
    }
    

    HandleConnect() can be completed in another thread even before async_wait() (unlikely but possible). Do I have to strand wrap Start(), HandleConnect(), and HandleTimeout()?

  2. What if HandleConnect() is called first without error, but deadline_timer.cancel() or deadline_timer.expires_from_now() fails because HandleTimeout() "have been queued for invocation in the near future"? Looks like example code lets HandleTimeout() close socket. Such behavior (timer closes connection after we happily started some operations after connect) can easily lead to serious headache.

  3. What if HandleTimeout() and socket.close() are called first. Is it possible to HandlerConnect() be already "queued" without error? Documentation says: "Any asynchronous send, receive or connect operations will be cancelled immediately, and will complete with the boost::asio::error::operation_aborted error". What does "immediately" mean in multithreading environment?

Upvotes: 0

Views: 824

Answers (1)

Igor R.
Igor R.

Reputation: 15075

  1. You should wrap with strand each handler, if you want to prevent their parallel execution in different threads. I guess some completion handlers would access socket_ or the timer, so you'll definitely have to wrap Start() with a strand as well. But wouldn't it be much more simple to use io_service-per-CPU model, i.e. to base your application on io_service pool? IMHO, you'll get much less headache.

  2. Yes, it's possible. Why is it a headache? The socket gets closed because of a "false timeout", and you start re-connection (or whatever) procedure just as if it were closed due to a network failure.

  3. Yes, it's also possible, but again, it shouldn't cause any problem for correctly designed program: if in HandleConnect you try to issue some operation on a closed socket, you'll get the appropriate error. Anyway, when you attempt to send/receive data you don't really know the current socket/network status.

Upvotes: 1

Related Questions