在asio的堆栈式协程中直接使用spawn是否安全?

4
当我在协程中使用spawn启动一个新的stackfull协程时,valgrind会提示许多使用未初始化值(valgrind输出)。
然后我使用io_service.post调用处理程序,在其中启动一个新的stackfull协程,一切都很正常。
我已经搜索并阅读了一些文档,但找不到有关如何在stackfull协程中安全地创建新的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,post + spawn将启动新的stackfull协程。

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

1个回答

4

这是安全的。

Boost.Asio对Boost.Coroutine的一流支持是一个薄的外观,具有两个值得注意的行为:

  • 使用strand作为执行上下文的协程和处理程序。这保证了协程在yield之前不会被恢复。
  • 如果检测到没有可用于恢复它的处理程序,Boost.Asio将防止协程无限期地挂起。在这种情况下,Boost.Asio将销毁协程,导致挂起的堆栈解除。有关详细信息,请参见答案。

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


谢谢。我使用spawn(yield_context)重载来创建一个新的协程(源代码)。当我以valgrind ./a.out运行程序时,valgrind仍然报告大量的“使用未初始化的大小为8的值”。这是输出。并且在运行./a.out后,valgrind出现了“段错误”。我做错了什么吗? - cfy
这是否意味着使用boost asio stackfull coroutine的程序不适合使用valgrind - cfy
3
你是否在明确使用Boost.Coroutine中的支持valgrind进行构建?valgrind=on b2命令行选项定义了BOOST_USE_VALGRIND,从而使分配的堆栈被Valgrind注册。 - Tanner Sansbury
就像你所说的那样,使用valgrind=on编译boost并在我的代码中定义BOOST_USE_VALGRIND,让valgrind感到满意。谢谢。 - cfy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接