c++ - boost asio doc中教程的奇怪输出

标签 c++ multithreading boost-asio

在第 5 篇教程中,我在问题底部给出的代码,asio 文档介绍了输出如下:

Timer 2: 0
Timer 1: 1
Timer 2: 2
Timer 1: 3
Timer 2: 4
.
.
.

在第一个之后,它是可以预期的,具有顺序。
但是即使 Timer1 首先被包裹在 strand 中,为什么 Timer 2 先开始运行?
#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;
}

最佳答案

一个 strand 用于提供处理程序的串行执行。此外,在某些条件下,它为通过链发布或分派(dispatch)的处理程序的调用顺序提供保证。该示例不满足这些条件。此外,不能保证会观察到完成处理程序之间的交替模式。

IO 对象,例如计时器,不被链包裹,完成处理程序是。一个 strand可以被认为与处理程序的 FIFO 队列相关联。如果处理程序队列当前没有处理程序发布到 io_service ,然后它会从自身弹出一个处理程序并将其发布到相关的io_service .此流程保证不会同时调用发布到同一链中的处理程序。

  • strand.post() 将处理程序排入链中。
  • strand.dispatch() 如果当前调用者正在链的上下文中运行,则将运行处理程序。否则,它将像 post() 一样将处理程序排入队列。 .
  • strand.wrap() 返回一个新的完成处理程序,当它被调用时,将 dispatch()包裹的处理程序进入链。本质上,wrap()将处理程序的分派(dispatch)延迟到链中。

  • 给定完成处理程序 ab , 如果 ab 之前入队,然后 a将在 b 之前调用.这是所有场景都可以减少的根本保证。 a 的场景在 b 之前保证是 documented如下:
  • 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) 之前.
  • io_service makes no guarantees关于处理程序的调用顺序。此外,从 strand.wrap() 返回的处理程序不在一个链的上下文中运行。示例代码简化为:

    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()以未指定的顺序排入链中。
    wrapped_print 的未指定顺序被调用是为什么不能保证观察到 print1 之间的交替模式。和 print2原始示例中的处理程序。然而,鉴于 io_service 的当前实现的内部调度程序,人们会观察到这样的模式。

    关于c++ - boost asio doc中教程的奇怪输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28010880/

    相关文章:

    java - 为什么弱连接时 tcp 数据发送会中断

    c++ - 单线程程序明显使用多核

    java - 使用线程填充 JList

    c++ - 这个 boost::asio 和 boost::coroutine 使用模式有什么问题?

    android - Asio 或 Boost.Asio 可以在 iPhone 或 Android 上运行吗?

    c++ - 模运算——竞技编程

    c++ - OpenMP 和优化 vector 运算

    c++ - 无法从线程类获得 100% 的 CPU 使用率

    c# - 在 ASP.net 解决方案中使用 Unity IOC 容器

    c++ - 如何重新启动升压截止时间计时器