在asio stackful协同程序中直接使用产卵是否安全

Is it safe to use spawn directly in an asio stackful coroutine?

本文关键字:安全 是否 stackful asio 程序      更新时间:2023-10-16

当我使用spawn在协同程序中启动一个新的堆栈完整协同程序时,valgrind说很多都使用了未初始化的值(valgrind输出)。

然后我使用io_service.post调用一个处理程序,并在其中启动一个新的stackfull协程,一切似乎都很好。

我已经搜索并阅读了一些文档,但找不到关于如何在堆栈完整协程中安全地创建新的堆栈完整协程的信息。

这是代码:

#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/system_timer.hpp>
#include <chrono>
using namespace std;
int main()
{
    auto use_post = false;
    boost::asio::io_service io_service;
    boost::asio::spawn(io_service,
                       [&io_service, &use_post](boost::asio::yield_context yield){
        if(use_post){
            io_service.post([&io_service]{
                boost::asio::spawn(io_service, [&io_service](boost::asio::yield_context yield){
                    boost::asio::system_timer timer(io_service);
                    timer.expires_from_now(std::chrono::seconds(1));
                    timer.async_wait(yield);
                    cout << "Sleep 1 second" << endl;
                });
            });
        }
        else{
            boost::asio::spawn(io_service, [&io_service](boost::asio::yield_context yield){
                boost::asio::system_timer timer(io_service);
                timer.expires_from_now(std::chrono::seconds(1));
                timer.async_wait(yield);
                cout << "Sleep 1 second" << endl;
            });
        }
        boost::asio::system_timer timer(io_service);
        timer.expires_from_now(std::chrono::seconds(2));
        timer.async_wait(yield);
        cout << "Sleep 2 seconds" << endl;
    });
    io_service.run();
    return 0;
}

如果use_post变量设置为true,则新的stackfull协同程序将通过post+spawn启动。

也许我没有仔细阅读这些文档,在Boost.Asio C++ Network ProgrammingN4045和boost asio文档中找不到任何有用的东西。

它是安全的。

Boost。Asio对Boost的一流支持。Coroutine是一个薄薄的外表,有两个显著的行为:

  • 协程和恢复它的处理程序使用strand作为它们的执行上下文。这保证了协同程序在产生结果之前不会恢复
  • 如果检测到没有可用的处理程序来恢复协程,Boost.Asio将阻止协程无限期暂停。当这种情况发生时,Boost.Asio将破坏协程,导致暂停的堆栈展开。有关详细信息,请参阅此答案

在上面的示例代码中,spawn(io_service&)重载导致生成的协程具有自己的strand。因此,如果多个线程正在运行io_service,则每个协程都可以并行运行,但不能保证这样做。另一方面,如果使用spawn(yield_context)重载,则新的协程将具有与调用协程相同的执行上下文(即strand),从而阻止并行执行。