I am not sure about one detail related to strands.
Suppose the following situation: two independent objects each one with his own strand. And each strand related to one common io_service. Each object use his strand for posting and wrapping async operations. If I have this (unique) io_service .run()'ing on several threads, I am not sure if the following will happen:
All operations posted and async wrapped by one of the objects will be executed non concurrently. So all operations related to one of the objects will be executed serially (Posted operations will be executed in the same order than they were posted. Wrapped async operations will be executed in an unspecified order because they are asynchronous but still being executed serially).
Two operations originated in different objects (and therefore posted or wrapped from different strand objects related to the same io_service) could be executed concurrently.
In summary, each object will execute his posted and wrapped handlers serially but handlers posted and wrapped from different objects (strands) will execute concurrently.
+-----------------+ +-----------------+
| Obj1 | | Obj2 |
| +-------------+ | | +-------------+ |
| | Strand_1 | | | | Strand_2 | |
| +-------------+ | | +-------------+ |
+--------+--------+ +-------+---------+
| |
+--------+ +-------+
| |
+----+--+----+
| io_service |
+------------+
|
|
+--------+-------+
| |
Thread1 Thread_2
io_service.run() io_service.run()
Am I right?
Thank you
If the run() method is called on an object of type boost::asio::io_service, the associated handlers are invoked on the same thread. By using multiple threads, an application can call multiple run() methods simultaneously.
Asio defines boost::asio::io_service , a single class for an I/O service object. Every program based on Boost. Asio uses an object of type boost::asio::io_service . This can also be a global variable. While there is only one class for an I/O service object, several classes for I/O objects exist.
The boost::asio::bind_executor() function is a helper to bind a specific executor object, such as a strand, to a completion handler. This binding automatically associates an executor as shown above. For example, to bind a strand to a completion handler we would simply write: my_socket.
At its core, Boost Asio provides a task execution framework that you can use to perform operations of any kind. You create your tasks as function objects and post them to a task queue maintained by Boost Asio. You enlist one or more threads to pick these tasks (function objects) and invoke them.
In short, a strand
guarantees sequential invocation of its own handlers, but makes no guarantee of concurrent execution of handlers from different strands. Thus, the answers to the points are:
A strand
maintains its own handler queue, and guarantees that only one of its handlers is in the io_service
, resulting in handlers being synchronized before being placed into the io_service
. Thus, all handlers posted or dispatched through a strand
will be executed sequentially.
Concurrent execution of handlers posted or dispatched through different strand
s can occur, it is just not guaranteed to occur. The documentation states:
The implementation makes no guarantee that handlers posted or dispatched through different strand objects will be invoked concurrently.
Therefore, if Thread1
is executing a handler posted through Strand_1
, Boost.Asio will not use that information to guarantee that a handler posted through Strand_2
will be executed by Thread2
; however, it is possible that Thread2
is selected to execute the handler from Strand_2
based on other implementation details, such as being the next available thread in the list of threads running the io_service
.
For example, consider the case where 3 handlers A
, B
, and C
are ready to run within the io_service
:
A
was posted posted through Strand_1
.B
was not posted through a strand
.C
was posted through Strand_2
.If Thread1
and Thread2
are running the io_service
, then one possible execution order is:
Thread1 | Thread2
----------------+----------------
start A() | start B()
`-- finish A() | |
start C() | `-- finish B()
`-- finish C() |
The illustrated execution order shows that that handlers (A
and C
) posted through different strand
s (Strand_1
and Strand_2
respectively) are not guaranteed to be executed concurrently.
All operations posted and async wrapped by one of the objects will be executed non concurrently. So all operations related to one of the objects will be executed serially (Posted operations will be executed in the same order than they were posted. Wrapped async operations will be executed in an unspecified order because they are asynchronous but still being executed serially).
Yes.
Two operations originated in different objects (and therefore posted or wrapped from different strand objects related to the same io_service) could be executed concurrently.
Yes
In summary, each object will execute his posted and wrapped handlers serially but handlers posted and wrapped from different objects (strands) will execute concurrently.
Yes
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With