如何为 co_spawn 生成的协程创建 shared_ptr?

问题描述 投票:0回答:1

我正在尝试实现一些称为

co_spawn_guard
的原语,它采用与
asio::co_spawn
相同的参数运行传递协程并返回
shared_ptr
。这个
shared_ptr
指向协程守卫类,当这个类被销毁时,它会发出生成的协程的取消信号。

一切听起来很简单,但我遇到了段错误并且不知道为什么。我会很感激一些提示。

这里有一个完整的例子

#include <cstdint>
#include <list>
#include <vector>
#include <iostream>
#include <concepts>
#include <type_traits>
#include <memory>
#include <thread>
#include <chrono>
 
#define ASIO_HAS_STD_SYSTEM_ERROR

#include <boost/asio.hpp>
#include <boost/asio/experimental/channel.hpp>
#include <boost/asio/experimental/as_tuple.hpp>

using namespace boost;


class coro_guard;

template<typename Executor, typename Awaitable, typename CompletionToken>
std::shared_ptr<coro_guard> co_spawn_guard(Executor, Awaitable&&, CompletionToken&&);
    
class coro_guard : public std::enable_shared_from_this<coro_guard>
{
public:

    template<typename Executor, typename Awaitable, typename CompletionToken>
    friend std::shared_ptr<coro_guard> co_spawn_guard(Executor, Awaitable&&, CompletionToken&&);

    template<typename... Args>
    [[nodiscard]] static std::shared_ptr<coro_guard> create(Args&&... args) 
    {
        return std::shared_ptr<coro_guard>(new coro_guard(std::forward<Args>(args)...));
    }

    coro_guard(const coro_guard&) =delete;;
    coro_guard(coro_guard&&) = delete;
    coro_guard& operator=(const coro_guard&) = delete;
    coro_guard& operator=(coro_guard&&) = delete;

    ~coro_guard()
    {
        asio::post(ex, [cancellation_signal_ptr = cancellation_signal_ptr_]()
        {
            cancellation_signal_ptr->emit(asio::cancellation_type::terminal);
        });
    }

private:
    asio::any_io_executor ex;
    std::shared_ptr<asio::cancellation_signal> cancellation_signal_ptr_;

    explicit coro_guard(asio::any_io_executor e) : ex{e}, cancellation_signal_ptr_{new asio::cancellation_signal{}}{}
};


template<typename Awaitable>
asio::awaitable<void> internal_coro(Awaitable&& a, std::shared_ptr<asio::cancellation_signal> ptr)
{
    std::cout<<"DEBUG internal_coro enter\n";
    co_await std::move(a);
    std::cout<<"DEBUG internal_coro exit\n";
    co_return;
}

template<typename Executor, typename Awaitable, typename CompletionToken>
std::shared_ptr<coro_guard> co_spawn_guard(Executor ex, Awaitable&& a, CompletionToken&& token)
{
    std::shared_ptr<coro_guard> guard =coro_guard::create(ex);
    asio::co_spawn(ex, internal_coro(std::move(a), guard->cancellation_signal_ptr_), asio::bind_cancellation_slot(guard->cancellation_signal_ptr_->slot(), std::forward<CompletionToken>(token)));
    return guard;
}

asio::awaitable<void> test_coro()
{
    std::cout<<"DEBUG internal_coro enter\n";
    std::cout<<"DEBUG internal_coro exit\n";
    co_return;
}

int main()
{
    asio::io_context io_context;

    auto ptr =co_spawn_guard(io_context.get_executor(), test_coro(), asio::detached);

    io_context.run();
    std::cout<<"dupa\n";
}
c++ boost-asio c++-coroutine boost-coroutine
1个回答
0
投票

Coros 不能引用他们的论点,除非他们的生命周期得到保证。改变这个:

asio::awaitable<void> internal_coro(Awaitable& a, std::shared_ptr<asio::cancellation_signal> ptr) {

asio::awaitable<void> internal_coro(Awaitable a, std::shared_ptr<asio::cancellation_signal> ptr) {

此外,

std::move
在“通用参考”上是不安全的。在这里使用
std::forward

asio::co_spawn(ex, internal_coro(std::move(a), guard->cancellation_signal_ptr_),
               asio::bind_cancellation_slot(guard->cancellation_signal_ptr_->slot(),
                                            std::forward<CompletionToken>(token)));

应该是

asio::co_spawn(ex, internal_coro(std::forward<Awaitable>(a), guard->cancellation_signal_ptr_),
               asio::bind_cancellation_slot(guard->cancellation_signal_ptr_->slot(),
                                            std::forward<CompletionToken>(token)));

最后,我觉得这可能有点过于复杂,并且有一些明显的设计缺陷。例如,您建议您在

co_spawn_guard
上接受任意完成标记。然而,它们中的大多数都没有任何意义,因为您忽略了使用
asio::co_spawn
.

返回的值
© www.soinside.com 2019 - 2024. All rights reserved.