问题描述
在第5个教程中,我在问题底部给出了代码,asio文档介绍了输出,如下所示:
In the 5th tutorial, of which the code I have given at bottom of the question, asio documentation introduced the output comes as follows :
Timer 2: 0
Timer 1: 1
Timer 2: 2
Timer 1: 3
Timer 2: 4
.
.
.
在第一个之后,按预期顺序进行.但是,即使Timer1首先包装在链中,为什么Timer 2首先开始运行?
After the first one it is as expectable, with the sequence.But even though Timer1 is wrapped in the strand first, why does Timer 2 starts running first ?
#include <iostream>
#include <asio.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
class printer
{
public:
printer(asio::io_service& io)
: strand_(io),
timer1_(io, boost::posix_time::seconds(1)),
timer2_(io, boost::posix_time::seconds(1)),
count_(0)
{
timer1_.async_wait(strand_.wrap(boost::bind(&printer::print1, this)));
timer2_.async_wait(strand_.wrap(boost::bind(&printer::print2, this)));
}
~printer()
{
std::cout << "Final count is " << count_ << "\n";
}
void print1()
{
if (count_ < 10)
{
std::cout << "Timer 1: " << count_ << "\n";
++count_;
timer1_.expires_at(timer1_.expires_at() + boost::posix_time::seconds(1));
timer1_.async_wait(strand_.wrap(boost::bind(&printer::print1, this)));
}
}
void print2()
{
if (count_ < 10)
{
std::cout << "Timer 2: " << count_ << "\n";
++count_;
timer2_.expires_at(timer2_.expires_at() + boost::posix_time::seconds(1));
timer2_.async_wait(strand_.wrap(boost::bind(&printer::print2, this)));
}
}
private:
asio::strand strand_;
asio::deadline_timer timer1_;
asio::deadline_timer timer2_;
int count_;
};
int main()
{
asio::io_service io;
printer p(io);
asio::thread t(boost::bind(&asio::io_service::run, &io));
io.run();
t.join();
system("PAUSE");
return 0;
}
推荐答案
A strand
用于提供处理程序的串行执行.同样,在某些条件下,它可以保证通过该链发布或调度的 handler 的调用顺序.该示例不满足这些条件.此外,不能保证将观察到完成处理程序之间的交替模式.
A strand
is used to provide serial execution of handlers. Also, under certain conditions, it provides a guarantee on the order of invocation of handlers posted or dispatched through the strand. The example does not meet these conditions. Furthermore, there is no guarantee that one will observe the alternating pattern between the completion handlers.
IO对象(例如计时器)不由子线包装,而完成处理程序则由.可以将strand
视为与处理程序的FIFO队列相关联.如果一个处理程序队列当前没有任何处理程序发布到io_service
中,则它将从自身弹出一个处理程序并将其发布到关联的io_service
中.此流程确保发布到同一链中的处理程序不会被同时调用.
IO Objects, such as timers, are not wrapped by strands, completion handlers are. A strand
can be thought of as being associated with a FIFO queue of handlers. If a handler queue has no handlers currently posted into an io_service
, then it will pop one handler from itself and post it into the associated io_service
. This flow guarantees that handlers posted into the same strand will not be invoked concurrently.
-
strand.post()
将处理程序加入链中. -
strand.dispatch()
如果当前调用者在该链的上下文中运行,则a>将运行处理程序.否则,它将像post()
一样使处理程序进入队列. -
strand.wrap()
返回一个新的完成处理程序,该处理程序在被调用时会将包装的处理程序dispatch()
放入链中.本质上,wrap()
将处理程序的分派推迟到该链中.
strand.post()
enqueues a handler into the strand.strand.dispatch()
will run the handler if the current caller is running within the context of the strand. Otherwise, it will enqueue the handler as if bypost()
.strand.wrap()
return a new completion handler that, when invoked, willdispatch()
the wrapped handler into the strand. Essentially,wrap()
defers the dispatching of a handler into the strand.
给出完成处理程序a
和b
,如果a
在b
之前排队,则a
将在b
之前调用.这是可以减少所有情况的基本保证.在b
之前保证a
的方案是已记录,如下所示:
Given completion handlers a
and b
, if a
is enqueued before b
, then a
will be invoked before b
. This is the fundamental guarantee to which all scenarios can be reduced. The scenarios in which a
is guaranteed before b
are documented as followed:
-
strand.post(a)
发生在strand.post(b)
之前.由于post()
不会尝试调用post()
中提供的处理程序,因此a
在b
之前排队. -
strand.post(a)
发生在strand.dispatch(b)
之前,其中strand.dispatch(b)
在链外执行.当strand.dispatch(b)
出现在一条链之外时,b
就像被post()
一样排队.因此,这可以减少到strand.post(a)
在strand.post(b)
之前发生. -
strand.dispatch(a)
发生在strand.post(b)
之前,其中strand.dispatch(a)
发生在一条链之外.当strand.dispatch(a)
发生在一条链之外时,a
就像被post()
一样排队.因此,这可以减少到strand.post(a)
在strand.post(b)
之前发生. -
strand.dispatch(a)
发生在strand.dispatch(b)
之前,其中两者均在链外执行.由于没有发生在一个链中,因此两个处理程序都按post()
排队.因此,这可以减少到strand.post(a)
在strand.post(b)
之前发生.
strand.post(a)
happens beforestrand.post(b)
. Aspost()
does not attempt to invoke the provided handler withinpost()
,a
is enqueued beforeb
.strand.post(a)
happens beforestrand.dispatch(b)
, wherestrand.dispatch(b)
is performed outside of a strand. Asstrand.dispatch(b)
occurs outside of a strand,b
is queued as if bypost()
. Thus, this reduces down tostrand.post(a)
happening beforestrand.post(b)
.strand.dispatch(a)
happens beforestrand.post(b)
, wherestrand.dispatch(a)
occurs outside of a strand. Asstrand.dispatch(a)
occurs outside of a strand,a
is queued as if bypost()
. Thus, this reduces down tostrand.post(a)
happening beforestrand.post(b)
.strand.dispatch(a)
happens beforestrand.dispatch(b)
, where both are performed outside of the strand. As neither occur within a strand, both handlers are enqueued as if bypost()
. Thus, this reduces down tostrand.post(a)
happening beforestrand.post(b)
.
io_service
对处理程序的调用顺序不做任何保证.此外,从strand.wrap()
返回的处理程序不在链的上下文中运行.该示例代码简化为:
The io_service
makes no guarantees about the invocation order of handlers. Additionally, the handler returned from strand.wrap()
does not run within the context of a strand. The example code simplifies to:
auto wrapped_print1 = strand.wrap(&print1);
auto wrapped_print2 = strand.wrap(&print2);
timer1_.async_wait(wrapped_print1);
timer2_.async_wait(wrapped_print2);
如果async_wait
操作同时完成,则wrapped_print1
和wrapped_print2
完成处理程序将发布到io_service
中以进行延迟调用.由于io_service
不能保证调用顺序,因此它可以选择首先调用wrapped_print1
,或者可以选择首先调用wrapped_print2
.这两个wrapped_print
处理程序都以未指定的顺序在该链的上下文之外被调用,导致print1()
和print2()
被以未指定的顺序排队到该链中.
If the async_wait
operations complete at the same time, the wrapped_print1
and wrapped_print2
completion handlers will be posted into the io_service
for deferred invocation. As the io_service
makes no guarantees on the invocation order, it may choose to invoke wrapped_print1
first, or it may choose to invoke wrapped_print2
first. Both wrapped_print
handlers are being invoked outside of the context of the strand in an unspecified order, resulting in print1()
and print2()
being enqueued into the strand in an unspecified order.
调用wrapped_print
的未指定顺序是为什么不能保证在原始示例中观察到print1
和print2
处理程序之间的交替模式的原因.但是,考虑到io_service
内部调度程序的当前实现,人们将观察到这种模式.
The unspecified order in which wrapped_print
are invoked is why one is not guaranteed to observe an alternating pattern between the print1
and print2
handlers in the original example. However, given the current implementation of the io_service
's internal scheduler, one will observe such a pattern.
这篇关于Boost Asio Doc中的教程的奇怪输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!