ASIO C++协程取消
ASIO C++ coroutine cancellation
我正在生成一个协程,如下所示。
asio::co_spawn(executor, my_coro(), asio::detached);
我该如何取消它?
据我所知,可以通过将处理程序与 asio::bind_cancellation_slot
绑定来简单地实现每个处理程序的取消。这在我的具体示例中不起作用(无论使用 asio::detached“处理程序”或某些 lambda),而且它不起作用对我来说很有意义。
我发现 this blog post 基本上是说从另一个协程生成协程并等待它(使用适当的 asio::bind_cancellation_slot
设置)就可以了。这对我来说失败了,因为在下面的例子中 my_coro
似乎从来没有 运行。此外,我什至不知道为什么这会起作用(关于取消)。
asio::awaitable<void> cancelable(asio::cancellation_signal& sig, asio::awaitable<void>&& awaitable) {
co_await asio::co_spawn(co_await asio::this_coro::executor, std::move(awaitable), asio::bind_cancellation_slot(sig.slot(), asio::use_awaitable));
co_return;
}
// ...
asio::cancellation_signal signal;
asio::co_spawn(executor, cancelable(signal, my_coro()), asio::detached);
在ASIO中将asio::cancellation_signal
连接到协程(由co_await asio::this_coro::cancellation_state
获得)的asio::cancellation_state
的正确方法是什么?
如果有帮助:我在最新的 master 上使用独立的 ASIO,即不是 boost 版本。
要在 asio 中取消协程,请使用新的 awaitable_operator '||'。可等待的运算符“||”允许 co_await 多个协程,直到其中一个协程完成。例如:
#include "boost/asio/experimental/awaitable_operators.hpp"
#include <boost/asio.hpp>
#include <boost/asio/deadline_timer.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/system_timer.hpp>
#include <boost/asio/this_coro.hpp>
#include <chrono>
#include <iostream>
boost::asio::awaitable<void>
printHelloEverySecond ()
{
for (;;)
{
std::cout << "Hello" << std::endl;
boost::asio::system_timer timer{ co_await boost::asio::this_coro::executor };
timer.expires_after (std::chrono::seconds{ 1 });
co_await timer.async_wait (boost::asio::use_awaitable);
}
}
boost::asio::awaitable<void>
stopAfter4500Milliseconds (boost::asio::system_timer &timer)
{
boost::asio::system_timer stopAfterFiveSeconds{ co_await boost::asio::this_coro::executor };
stopAfterFiveSeconds.expires_after (std::chrono::milliseconds{ 4500 });
co_await stopAfterFiveSeconds.async_wait (boost::asio::use_awaitable);
timer.cancel ();
}
boost::asio::awaitable<void>
cancel (boost::asio::system_timer &timer)
{
try
{
co_await timer.async_wait (boost::asio::use_awaitable);
}
catch (boost::system::system_error &e)
{
using namespace boost::system::errc;
if (operation_canceled == e.code ())
{
// swallow cancel
}
else
{
std::cout << "error in timer boost::system::errc: " << e.code () << std::endl;
abort ();
}
}
}
int
main ()
{
boost::asio::io_context ioContext{};
boost::asio::system_timer timer{ ioContext };
timer.expires_at (std::chrono::system_clock::time_point::max ());
using namespace boost::asio::experimental::awaitable_operators;
co_spawn (ioContext, printHelloEverySecond () || cancel (timer), [] (auto, auto) { std::cout << "stopped" << std::endl; });
co_spawn (ioContext, stopAfter4500Milliseconds (timer), boost::asio::detached);
ioContext.run ();
}
此处“printHelloEverySecond ()”将运行 直到“cancel()”returns 成功,这发生在定时器在 4500 毫秒后取消(在“stopAfter4500Milliseconds”中)。这允许在计时器被取消时取消“printHelloEverySecond ()”。
供参考:
Chris Kohlhoff explains awaitable_operator and cancelation
我正在生成一个协程,如下所示。
asio::co_spawn(executor, my_coro(), asio::detached);
我该如何取消它?
据我所知,可以通过将处理程序与 asio::bind_cancellation_slot
绑定来简单地实现每个处理程序的取消。这在我的具体示例中不起作用(无论使用 asio::detached“处理程序”或某些 lambda),而且它不起作用对我来说很有意义。
我发现 this blog post 基本上是说从另一个协程生成协程并等待它(使用适当的 asio::bind_cancellation_slot
设置)就可以了。这对我来说失败了,因为在下面的例子中 my_coro
似乎从来没有 运行。此外,我什至不知道为什么这会起作用(关于取消)。
asio::awaitable<void> cancelable(asio::cancellation_signal& sig, asio::awaitable<void>&& awaitable) {
co_await asio::co_spawn(co_await asio::this_coro::executor, std::move(awaitable), asio::bind_cancellation_slot(sig.slot(), asio::use_awaitable));
co_return;
}
// ...
asio::cancellation_signal signal;
asio::co_spawn(executor, cancelable(signal, my_coro()), asio::detached);
在ASIO中将asio::cancellation_signal
连接到协程(由co_await asio::this_coro::cancellation_state
获得)的asio::cancellation_state
的正确方法是什么?
如果有帮助:我在最新的 master 上使用独立的 ASIO,即不是 boost 版本。
要在 asio 中取消协程,请使用新的 awaitable_operator '||'。可等待的运算符“||”允许 co_await 多个协程,直到其中一个协程完成。例如:
#include "boost/asio/experimental/awaitable_operators.hpp"
#include <boost/asio.hpp>
#include <boost/asio/deadline_timer.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/system_timer.hpp>
#include <boost/asio/this_coro.hpp>
#include <chrono>
#include <iostream>
boost::asio::awaitable<void>
printHelloEverySecond ()
{
for (;;)
{
std::cout << "Hello" << std::endl;
boost::asio::system_timer timer{ co_await boost::asio::this_coro::executor };
timer.expires_after (std::chrono::seconds{ 1 });
co_await timer.async_wait (boost::asio::use_awaitable);
}
}
boost::asio::awaitable<void>
stopAfter4500Milliseconds (boost::asio::system_timer &timer)
{
boost::asio::system_timer stopAfterFiveSeconds{ co_await boost::asio::this_coro::executor };
stopAfterFiveSeconds.expires_after (std::chrono::milliseconds{ 4500 });
co_await stopAfterFiveSeconds.async_wait (boost::asio::use_awaitable);
timer.cancel ();
}
boost::asio::awaitable<void>
cancel (boost::asio::system_timer &timer)
{
try
{
co_await timer.async_wait (boost::asio::use_awaitable);
}
catch (boost::system::system_error &e)
{
using namespace boost::system::errc;
if (operation_canceled == e.code ())
{
// swallow cancel
}
else
{
std::cout << "error in timer boost::system::errc: " << e.code () << std::endl;
abort ();
}
}
}
int
main ()
{
boost::asio::io_context ioContext{};
boost::asio::system_timer timer{ ioContext };
timer.expires_at (std::chrono::system_clock::time_point::max ());
using namespace boost::asio::experimental::awaitable_operators;
co_spawn (ioContext, printHelloEverySecond () || cancel (timer), [] (auto, auto) { std::cout << "stopped" << std::endl; });
co_spawn (ioContext, stopAfter4500Milliseconds (timer), boost::asio::detached);
ioContext.run ();
}
此处“printHelloEverySecond ()”将运行 直到“cancel()”returns 成功,这发生在定时器在 4500 毫秒后取消(在“stopAfter4500Milliseconds”中)。这允许在计时器被取消时取消“printHelloEverySecond ()”。
供参考:
Chris Kohlhoff explains awaitable_operator and cancelation