strand
provides both the guarantee of not executing completion handlers concurrently and defines the order of handler invocation. In short, completion handlers posted into a strand
are executed in the same order in which they are posted.
Therefore:
strand_.post(&task1);
strand_.post(&task2);
strand_.post(&task3);
Guarantees order of handler invocation is task1
-> task2
-> task3
. However, wrapped completion handlers for asynchronous operations are not guaranteed, as the order in which asynchronous operations are performed is unspecified. For example, the following does not provide the same guarantee:
async_read(socket1, ..., strand_.wrap(&task1));
async_read(socket2, ..., strand_.wrap(&task2));
async_read(socket3, ..., strand_.wrap(&task3));
If completion handlers must be invoked in a specified order for asynchronous operations, then either:
- Queue completion handlers and manage the order manually.
- Serialize all asynchronous operations. For example,
async_op_1
's completion handler task1
initiates async_op_2
with a completion handler of task2
.
Here is the relevant excerpt from io_service::strand
's order of handler invocation documentation:
Given:
- a strand object
s
- an object
a
meeting completion handler requirements
- an object
a1
which is an arbitrary copy of a made by the implementation
- an object
b
meeting completion handler requirements
- an object
b1
which is an arbitrary copy of b made by the implementation
if any of the following conditions are true:
s.post(a)
happens-before s.post(b)
- ...
then asio_handler_invoke(a1, &a1)
happens-before
asio_handler_invoke(b1, &b1)
.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…