Boost Asio:实施“事件”?

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

使用 Boost Asio,我将如何实现一个“事件”类来恢复 C++20 协程?

有点像这样:

// Oversimplicated, but hopefully good enough as example
struct oneshot_event {
    void raise();
    async::awaitable<void> wait();
};

在哪里

wait()
可以被
co_await
ed并且协程一旦调用
raise()
就恢复协程。

我知道 Boost Asio 有(或曾经有?我在过时的文档中找到了它)一个可以 yield 的

coro
类,但这对我没有帮助,因为有多个事件可以等待。我也不确定所有这些
Boost.asio
Boost.coroutine
的东西是如何一起工作的

吐息番

c++ boost boost-asio coroutine
2个回答
0
投票

希望这就是你想要的:

#include <boost/asio.hpp>
#include <boost/asio/awaitable.hpp>
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/detached.hpp>
#include <iostream>
#include <memory>

namespace asio = boost::asio;
using asio::awaitable;
using asio::co_spawn;
using asio::detached;
using asio::use_awaitable;

// Struct representing an event that can be raised and waited upon
struct oneshot_event {
    asio::io_context& io_; // Reference to the IO context for async operations
    bool raised_ = false; // Flag indicating whether the event has been raised
    std::vector<std::shared_ptr<asio::steady_timer>> timers_; // Timers associated with the event
    
    // Constructor that takes an IO context reference
    oneshot_event(asio::io_context& io) : io_(io) {}

    // Raise the event, allowing waiting coroutines to resume
    void raise() {
        if (!raised_) {
            raised_ = true;
            for (auto& timer : timers_)
                timer->cancel();
        }
    }
    
    // Wait for the event to be raised
    awaitable<void> wait() {
        if (!raised_) {
            // Create a new shared_ptr to a timer and add it to the vector
            auto timer = std::make_shared<asio::steady_timer>(io_, std::chrono::seconds(0));
            timers_.push_back(timer);
            
            // Suspend the coroutine until the timer expires or is canceled
            co_await timer->async_wait(use_awaitable);
        }
    }
};

// Coroutine that waits for an event and resumes when the event is raised
awaitable<void> myCoroutine(oneshot_event& event) {
    std::cout << "Coroutine waiting...\n";
    co_await event.wait();
    std::cout << "Coroutine resumed!\n";
}

int main() {
    asio::io_context io;

    oneshot_event event(io);
    auto coroutine = myCoroutine(event);

    co_spawn(io, std::move(coroutine), detached);

    std::cout << "Sleeping for 3 seconds...\n";
    std::this_thread::sleep_for(std::chrono::seconds(3));

    event.raise();  // Resume the coroutine

    io.run();
    return 0;
}

输出:

Sleeping for 3 seconds...
Coroutine waiting...
Coroutine resumed!

0
投票

传统的答案会使用等待计时器(gera 发布了一个答案)。

但是,这可能容易出错且笨拙,尤其是对于多线程(两种竞争条件(例如 https://stackoverflow.com/a/22204127/85371,更具体地说 https://stackoverflow.com/a/43169596 /85371) 和数据竞争(例如 gera 的代码不是线程安全的)。

更灵活的是实验频道支持:https://www.boost.org/doc/libs/master/doc/html/boost_asio/overview/channels.html

这将允许您为多个事件使用多个通道,或者在单个通道上支持多个事件。通道以开箱即用的线程安全变体 (

asio::concurrent_channel
) 存在。

© www.soinside.com 2019 - 2024. All rights reserved.