【问题标题】:Is it safe to use spawn directly in an asio stackful coroutine?直接在 asio 堆栈协程中使用 spawn 是否安全?
【发布时间】:2015-05-24 16:36:52
【问题描述】:

当我使用 spawn 在协程中启动一个新的 stackfull 协程时,valgrind 说了很多使用未初始化的值(valgrind output)。

然后我使用 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,新的stackfull协程将通过post + spawn启动。

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

【问题讨论】:

    标签: c++ boost boost-asio coroutine


    【解决方案1】:

    很安全。

    Boost.Asio 对 Boost.Coroutine 的一流支持是一个具有两个显着行为的瘦外观:

    • 协程和恢复它的处理程序使用strand 作为其执行上下文。这保证了协程在它产生之前不会被恢复。
    • Boost.Asio 防止协程在检测到没有可恢复的处理程序时无限期挂起。发生这种情况时,Boost.Asio 将销毁协程,导致挂起的堆栈展开。更多详情请参阅this 回答。

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

    【讨论】:

    • 谢谢。我使用spawn(yield_context) 重载来创建一个新的协程(source code)。当我以valgrind ./a.out 运行程序时,valgrind 仍然报告很多Use of uninitialised value of size 8。这是output。运行 ./a.out 后,valgrind 为 segmentation fault。我是不是做错了什么?
    • 这是否意味着valgrind不适合使用boost asio stackfull协程的程序?
    • @cfy 您是否明确使用 Boost.Coroutine 的 support for valgrind 进行构建? valgrind=on b2 命令行选项定义 BOOST_USE_VALGRIND,导致分配的堆栈注册到 Valgrind。
    • 如你所说,使用 valgrind=on 编译 boost 并在我的代码中定义 BOOST_USE_VALGRIND,让 valgrind 开心。谢谢。
    猜你喜欢
    • 2019-01-14
    • 2012-01-23
    • 2016-11-03
    • 1970-01-01
    • 2011-10-29
    • 1970-01-01
    • 1970-01-01
    • 2016-12-21
    • 2020-08-20
    相关资源
    最近更新 更多