1
0
mirror da https://github.com/tearshark/librf.git synced 2024-10-01 15:57:07 +08:00
librf/tutorial/test_async_stop_token.cpp
2021-11-02 17:15:17 +08:00

106 righe
2.9 KiB
C++
Originale Blame Cronologia

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <chrono>
#include <iostream>
#include <string>
#include <thread>
#include "librf/librf.h"
using namespace librf;
using namespace std::chrono;
//_Ctype签名:void(bool, int64_t)
template<class _Ctype, typename=std::enable_if_t<std::is_invocable_v<_Ctype, bool, int64_t>>>
static void callback_get_long_with_stop(stop_token token, int64_t val, _Ctype&& cb)
{
std::thread([val, token = std::move(token), cb = std::forward<_Ctype>(cb)]
{
for (int i = 0; i < 10; ++i)
{
if (token.stop_requested())
{
cb(false, 0);
return;
}
std::this_thread::sleep_for(10ms);
}
//有可能未检测到token的停止要求
//如果使用stop_callback来停止则务必保证检测到的退出要求是唯一的且线程安全的
//否则多次调用cb会导致协程在半退出状态下外部的awaitable_t管理的state获取跟root出现错误。
cb(true, val * val);
}).detach();
}
//token触发后设置canceled_exception异常。
static future_t<int64_t> async_get_long_with_stop(stop_token token, int64_t val)
{
awaitable_t<int64_t> awaitable;
//在这里通过stop_callback来处理退出并将退出转化为error_code::stop_requested异常。
//则必然会存在线程竞争问题导致协程提前于callback_get_long_with_stop的回调之前而退出。
//同时callback_get_long_with_stop还未必一定能检测到退出要求----毕竟只是一个要求,而不是强制。
callback_get_long_with_stop(token, val, [awaitable](bool ok, int64_t val)
{
if (ok)
awaitable.set_value(val);
else
awaitable.throw_exception(canceled_exception{error_code::stop_requested});
});
return awaitable.get_future();
}
//如果关联的协程被取消了则触发canceled_exception异常。
static future_t<int64_t> async_get_long_with_stop(int64_t val)
{
task_t* task = librf_current_task();
co_return co_await async_get_long_with_stop(task->get_stop_token(), val);
}
//测试取消协程
static void test_get_long_with_stop(int64_t val)
{
//异步获取值的协程
task_t* task = GO
{
try
{
int64_t result = co_await async_get_long_with_stop(val);
std::cout << result << std::endl;
}
catch (const std::logic_error& e)
{
std::cout << e.what() << std::endl;
}
};
//task的生命周期只在task代表的协程生存期间存在。
//但通过复制与其关联的stop_source生存期可以超过task的生存期。
stop_source stops = task->get_stop_source();
//取消上一个协程的延迟协程
GO
{
co_await sleep_for(1ms * (rand() % 300));
stops.request_stop();
};
this_scheduler()->run_until_notask();
}
void resumable_main_stop_token()
{
srand((int)time(nullptr));
for (int i = 0; i < 10; ++i)
test_get_long_with_stop(i);
std::cout << "OK - stop_token!" << std::endl;
}
#if LIBRF_TUTORIAL_STAND_ALONE
int main()
{
resumable_main_stop_token();
return 0;
}
#endif