Boost logo

Boost Users :

Subject: Re: [Boost-users] [boost.asio] Concurrently Ping 1000+ Hosts
From: Gavin Lambert (gavinl_at_[hidden])
Date: 2013-12-18 17:29:41

On 19/12/2013 11:12, Quoth Kyle Ketterer:
> In my Main thread, I was thinking about creating a vector of PingX
> objects. In the PingX class, I would have a separate io_service as well
> as wrap the async() functions in strands. I set the deadline timer at
> 800ms that way the io_service should return in less than a second. I
> would then call io_service run() in separate threads to *concurrently*
> ping these hosts.
> The problem appears to be that even through the async handers are
> wrapped in strands, there is data corruption. Is it true that when async
> handlers are wrapped in strands, they still cannot be executed
> *concurrently* ? My understanding of strand was that it serializes the
> handler functions to allow for thread safe access. However, I think that
> because I am accessing the same resources in multiple threads (such as
> the socket() object ), it is corrupting my expected output as well as
> occasionally throwing some exceptions.

It sounds like you're using the wrong approach.

You want one single io_service object, and one io_service::strand per
non-allowed-concurrency-task (possibly one per PingX object).

You can then start up any number of threads that you wish (don't do 1000
though -- typically maximum concurrency is achieved with somewhere
between #CPUs - #CPUs*2 threads) and have them all call run() on the
same shared io_service object.

Any handler that is queued via the same strand object will guarantee
that it is not executed concurrently with any other handler on the same
strand (but has no guarantees with handlers on other strands).
Additionally, even without strands you can guarantee that a handler
cannot execute before the line that does the async_* operation to start
it, and once called cannot execute again until you make another async_*
call from the handler (or elsewhere). Thus if your operations form a
single chain (such as a read that is started on construction and
continued only at the end of the handler) then those reads can't execute
concurrently with themselves even without a strand. (But you still
might want a strand or lock to protect data shared between read and
write, or between multiple concurrent writes, or separate objects with
shared data.)

Note that if you want the "ping"s to occur concurrently you'll have to
use different sockets for each one. Up to you whether you create one
socket for each PingX or make a smaller pool that is shared out as
needed (but the former is easier, and the second will need thread
protection on the pool).

Boost-users list run by williamkempf at, kalb at, bjorn.karlsson at, gregod at, wekempf at