【问题标题】:Weird output for a tutorial in boost asio docboost asio doc中教程的奇怪输出
【发布时间】:2015-01-18 14:36:54
【问题描述】:

在第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 是否真的介意包装的顺序,还是只是确保这些计时器不会同时运行?
  • 大胆猜测:从main 中删除io.run();线程t 已经调用它。这看起来像是一种竞争条件,可能会使有趣的事情成为可能。
  • 这就是本教程的重点。它展示了 strand 如何使从多个线程运行 io.run() 成为可能。当然,当你删除线程 t 时,一切正常。

标签: c++ multithreading boost-asio


【解决方案1】:

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


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

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

给定完成处理程序ab,如果ab 之前入队,那么a 将在b 之前被调用。这是所有场景都可以减少的根本保证。在b之前保证a的场景是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_servicemakes 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 调用的未指定顺序是为什么不能保证在原始示例中观察到 print1print2 处理程序之间的交替模式。然而,鉴于io_service 的内部调度程序的当前实现,人们会观察到这样一种模式。

【讨论】:

  • warp的存在是什么意思? warppostdispatch 看起来很相似,但 warp 并不能确保处理程序的执行顺序。你能解释一下within the context of the strand是什么(任何调用strand.post的函数都有临时变量的作用域,那么outside the context of the strand是什么?)和outside the strand? @Tanner Sansbury
猜你喜欢
  • 2023-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-13
  • 2011-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多