首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Boost asio C++ 20 Coroutines: co_spawn是一个具有引用参数意外结果的协同线。

Boost asio C++ 20 Coroutines: co_spawn是一个具有引用参数意外结果的协同线。
EN

Stack Overflow用户
提问于 2022-08-24 10:22:42
回答 1查看 250关注 0票数 3

在下面的代码中,会话协同线的参数通过引用传递。

代码语言:javascript
运行
复制
#include <boost/asio.hpp>
#include <iostream>

boost::asio::awaitable<void> session(const std::string& name)
{
    std::cout << "Starting " << name << std::endl;
    auto executor = co_await boost::asio::this_coro::executor;
}

int main()
{
    boost::asio::io_context io_context;

    co_spawn(io_context, session("ServerA"), boost::asio::detached);
    co_spawn(io_context, session("ServerB"), boost::asio::detached);

    io_context.run();

    return 0;
}

由于一些我不明白的原因,上面的代码导致打印启动ServerB两次。

代码语言:javascript
运行
复制
> g++ -std=c++20 ../test-coro.cpp -o test-coro && ./test-coro
Starting ServerB
Starting ServerB

但是,当我更改coroutine参数以传递值时,它将正确地打印启动ServerA启动ServerB

代码语言:javascript
运行
复制
#include <boost/asio.hpp>
#include <iostream>

boost::asio::awaitable<void> session(std::string name)
{
    std::cout << "Starting " << name << std::endl;
    auto executor = co_await boost::asio::this_coro::executor;
}

int main()
{
    boost::asio::io_context io_context;

    co_spawn(io_context, session("ServerA"), boost::asio::detached);
    co_spawn(io_context, session("ServerB"), boost::asio::detached);

    io_context.run();

    return 0;
}
代码语言:javascript
运行
复制
> g++ -std=c++20 ../test-coro.cpp -o test-coro && ./test-coro
Starting ServerA
Starting ServerB

它是预期的还是这是一个编译器/库错误?如果它是预期的,那么它的理由是什么呢?

环境:

Arch Linux 5.18.16-arch1-1

gcc (GCC) 12.2.0

boost版本1.79

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-08-24 10:47:23

您可以将coroutine状态想象为包含函数调用堆栈上的内容(这是函数恢复的原因):优先选择

当协同线开始执行时,它执行以下操作:

  • 使用运算符new分配coroutine状态对象(请参见下面)
  • 将所有函数参数复制到coroutine状态:移动或复制值参数,引用参数保持引用(如果在所引用对象结束后恢复协同线,则可能会出现悬空)。

coroutine逻辑上存储对临时字符串的引用。糟了。

我还没有检查过,但我假设Asio的可评估实现是从初始的suspend_always开始的(对于执行器模型,这对我来说很有直觉意义)。

是的,这意味着带有任何引用参数的co_spawn意味着必须保证引用对象的生存期。

在我的系统中,输出仅仅是

代码语言:javascript
运行
复制
Starting
Starting

一个解决办法就是你展示的东西。为了说明寿命方面:

代码语言:javascript
运行
复制
{
    std::string a="ServerA", b="ServerB";
    co_spawn(io_context, session(a), boost::asio::detached);
    co_spawn(io_context, session(b), boost::asio::detached);

    io_context.run();
}

也是一个有效的修补程序。对于这个简单的例子,我建议使用一个std::string_view,不管如何:

住在Coliru

代码语言:javascript
运行
复制
#include <boost/asio.hpp>
#include <iomanip>
#include <iostream>

boost::asio::awaitable<void> session(std::string_view name)
{
    std::cout << "Starting " << std::quoted(name) << std::endl;
    auto executor = co_await boost::asio::this_coro::executor;
}

int main()
{
    boost::asio::io_context io_context;

    std::string const a="ServerA";
    co_spawn(io_context, session(a), boost::asio::detached);
    co_spawn(io_context, session("ServerB"), boost::asio::detached);

    io_context.run();
}

打印

代码语言:javascript
运行
复制
Starting "ServerA"
Starting "ServerB"
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73471450

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档