I'd like to analyze the ordering of boost.asio calls using strand.
Consider the following scenario. First, a coroutine that uses the strand is called by boost::asio::spawn
(task 1), it's running exclusively since I use strand until it gets suspended cooperatively when instruction pointer reach ***, and the scheduler that runs on the thread executes the next handler (task 2).
Task 2 uses the same strand but it's called by boost::asio::post
. this call guarantee that this task get exclusiveness until finished (no yields).
So I expect that in this scenario, the remaining of task 1 won't be executed at least until task 2 finished. is my assumption correct ?
Furthermore, what if while task 2 being executed, more tasks are called on the same strand, does task 1 get priority when task 2 terminates, or there's no guarantee which task is going to take the strand (either task 2 that just return from yield or newer tasks that called)
//task1
boost::asio::spawn(strand_, [=](const auto& yield) {
...
..
.
auto response = sendRequest(request, yield); //(***)
...
..
.
}
//task 2
boost::asio::post(strand_, [&]() {
...
..
.
}
//task 3
boost::asio::post(strand_, [&]() {
...
..
.
}
So I expect that in this scenario, the remaining of task 1 won't be executed at least until task 2 finished. is my assumption correct ?
Yes
Furthermore, what if while task 2 being executed, more tasks are called on the same strand, does task 1 get priority when task 2 terminates, or there's no guarantee which task is going to take the strand (either task 2 that just return from yield or newer tasks that called)
If by "tasks are called" you mean "handlers are posted" (or equivalently: "async operations are initiated"), yes. All the tasks on a strand are executed in order they are posted.
This is documented here: Order Of Handler Invocation:
Order of handler invocation
Given: a strand object
s
- an object
a
meeting completion handler requirements- an object
a1
which is an arbitrary copy ofa
made by the implementation- an object
b
meeting completion handler requirements- an object
b1
which is an arbitrary copy ofb
made by the implementationif any of the following conditions are true:
s.post(a)
happens-befores.post(b)
s.post(a)
happens-befores.dispatch(b)
, where the latter is performed outside the strands.dispatch(a)
happens-befores.post(b)
, where the former is performed outside the strands.dispatch(a)
happens-befores.dispatch(b)
, where both are performed outside the strandthen
asio_handler_invoke(a1, &a1)
happens-beforeasio_handler_invoke(b1, &b1)
.
In your case the happens-before is present (because you know that task1's continuation MUST have been posted before task2 could be entered).