首页 > 解决方案 > Asio的执行流程是什么?

问题描述

我有一个测试程序如下:

io_service io;
deadline_timer t1(io);
deadline_timer t2(io);
t1.expires_from_now(boost::posix_time::seconds(10));
t1.async_wait([](const boost::system::error_code &error) {
    if (error == boost::asio::error::operation_aborted) {
        cout << "timer1 canceled" << endl;
    } else {
        cout << "timer1 expired" << endl;
    }
});

t2.expires_from_now(boost::posix_time::seconds(2));
t2.async_wait([&t1](const boost::system::error_code &error) {
    if (error == boost::asio::error::operation_aborted) {
        cout << "timer2 canceled" << endl;

    } else {
        t1.cancel();
        for (int i = 0; i < 5000000; i++) {
            cout << i << endl;
        }
        # usleep(1000000);
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));

        cout << "timer2 expired" << endl;
    }
});
io.run();

我想知道 timer2 何时到期并取消 timer1,“timer1 已取消”和“timer2 已到期”中的哪一个将首先打印?

结果是“timer2 已过期”。这是有道理的,因为单线程程序将执行直到某些“块”发生。

但是在插入“sleep_for(1000ms)”行(应该阻止执行,将进程转换为“Sleep”)之后,“timer2 expired”行仍然在“timer1 cancelled”行之前打印。

在我的想象中,boost:asio 是围绕“epoll”编写的,它可以处理“事件”,如来自网络的传入消息(timer2 到期)和“块”,如在单个线程中写入磁盘(睡眠)。但是为什么在“sleep_for”之后没有显示“timer1 cancelled”这一行?

问题 2:假设一个程序在一个线程中处理网络请求和 Chrono 作业。

void fun1(){
timer1.expire_from_now(3s);
timer1.async_wait([](const & error){
    cout<<"timer1 expired";
    heavy_job();
});
}

fun1 过期,执行cout<<"timer1 expired",但未执行。沉重的工作呢。这时,来自网络的请求触发了 fun2:

int wait_funcs= timer1.expire_from_now(3s);
if (wait_funcs == 0 ){
    job2();
}else{
    job3();
}

以下哪种情况会发生?

  1. heavy_job done -> job2: 这意味着 func1 不会被 fun2 中断,fun2 将在 fun1 完成(或阻塞?)后运行

  2. job2 done -> heavy_job: 这意味着 wait_funcs 检查检测到不安全行为

对不起我的演示,我是 boost:asio 的新手,很困惑。

标签: asynchronousboostboost-asio

解决方案


您可以将其io_service视为生产者-消费者队列:每当异步操作完成(或中止)时,其完成处理程序就会被推入队列;而另一方面,io_service::run()从队列中获取这些处理程序并调用它们。

还要注意,只要你的程序是单线程的(并且不使用协同程序),所有的完成处理程序总是一个接一个地顺序执行。

因此,在您的第一个示例中,t2计时器首先到期,然后调用完成处理程序。t1在前一个完成之前,不会从队列中获取的处理程序- 不管需要多长时间。

这同样适用于您的第二个示例: 的完成处理程序timer1正在 的上下文中运行io_service::run,因此后者无法获取任何后续处理程序,直到前一个处理程序完成。因此,如果heavy_job()完成时间过长,所有其他处理程序将被卡在队列中。


推荐阅读