Boost Asio Doc中的教程的奇怪输出 [英] Weird output for a tutorial in boost asio doc

查看:97
本文介绍了Boost Asio Doc中的教程的奇怪输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在第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

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() 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 by post().
  • strand.wrap() return a new completion handler that, when invoked, will dispatch() the wrapped handler into the strand. Essentially, wrap() defers the dispatching of a handler into the strand.

给出完成处理程序ab,如果ab之前排队,则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()中提供的处理程序,因此ab之前排队.
  • 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 before strand.post(b). As post() does not attempt to invoke the provided handler within post(), a is enqueued before b.
  • strand.post(a) happens before strand.dispatch(b), where strand.dispatch(b) is performed outside of a strand. As strand.dispatch(b) occurs outside of a strand, b is queued as if by post(). Thus, this reduces down to strand.post(a) happening before strand.post(b).
  • strand.dispatch(a) happens before strand.post(b), where strand.dispatch(a) occurs outside of a strand. As strand.dispatch(a) occurs outside of a strand, a is queued as if by post(). Thus, this reduces down to strand.post(a) happening before strand.post(b).
  • strand.dispatch(a) happens before strand.dispatch(b), where both are performed outside of the strand. As neither occur within a strand, both handlers are enqueued as if by post(). Thus, this reduces down to strand.post(a) happening before strand.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_print1wrapped_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的未指定顺序是为什么不能保证在原始示例中观察到print1print2处理程序之间的交替模式的原因.但是,考虑到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中的教程的奇怪输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆