TOSAsync
This commit is contained in:
163
Src/TOSAsync.hpp
163
Src/TOSAsync.hpp
@@ -1,77 +1,136 @@
|
||||
#pragma once
|
||||
|
||||
#include "boost/asio/awaitable.hpp"
|
||||
#include "boost/asio/co_spawn.hpp"
|
||||
#include "TOSLib.hpp"
|
||||
#include "boost/asio/associated_cancellation_slot.hpp"
|
||||
#include "boost/asio/associated_executor.hpp"
|
||||
#include "boost/asio/deadline_timer.hpp"
|
||||
#include "boost/asio/detached.hpp"
|
||||
#include "boost/asio/io_context.hpp"
|
||||
#include "boost/asio/use_awaitable.hpp"
|
||||
#include "boost/system/detail/error_code.hpp"
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/detached.hpp>
|
||||
#include <boost/asio/experimental/awaitable_operators.hpp>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
namespace TOS {
|
||||
|
||||
using namespace boost::asio::experimental::awaitable_operators;
|
||||
namespace asio = boost::asio;
|
||||
template<typename T = void>
|
||||
using coro = boost::asio::awaitable<T>;
|
||||
|
||||
class AsyncSemaphore
|
||||
{
|
||||
boost::asio::deadline_timer Deadline;
|
||||
std::atomic<uint8_t> Lock = 0;
|
||||
// class AsyncSemaphore
|
||||
// {
|
||||
// boost::asio::deadline_timer Deadline;
|
||||
// std::atomic<uint8_t> Lock = 0;
|
||||
|
||||
// public:
|
||||
// AsyncSemaphore(boost::asio::io_context& ioc)
|
||||
// : Deadline(ioc, boost::posix_time::ptime(boost::posix_time::pos_infin))
|
||||
// {}
|
||||
|
||||
// coro<> async_wait() {
|
||||
// try {
|
||||
// co_await Deadline.async_wait(boost::asio::use_awaitable);
|
||||
// } catch(boost::system::system_error code) {
|
||||
// if(code.code() != boost::system::errc::operation_canceled)
|
||||
// throw;
|
||||
// }
|
||||
|
||||
// co_await asio::this_coro::throw_if_cancelled();
|
||||
// }
|
||||
|
||||
// coro<> async_wait(std::function<bool()> predicate) {
|
||||
// while(!predicate())
|
||||
// co_await async_wait();
|
||||
// }
|
||||
|
||||
// void notify_one() {
|
||||
// Deadline.cancel_one();
|
||||
// }
|
||||
|
||||
// void notify_all() {
|
||||
// Deadline.cancel();
|
||||
// }
|
||||
// };
|
||||
|
||||
/*
|
||||
Многие могут уведомлять одного
|
||||
Ждёт события. После доставки уведомления ждёт повторно
|
||||
*/
|
||||
class MultipleToOne_AsyncSymaphore {
|
||||
asio::deadline_timer Timer;
|
||||
|
||||
public:
|
||||
AsyncSemaphore(
|
||||
boost::asio::io_context& ioc)
|
||||
: Deadline(ioc, boost::posix_time::ptime(boost::posix_time::pos_infin))
|
||||
MultipleToOne_AsyncSymaphore(asio::io_context &ioc)
|
||||
: Timer(ioc, boost::posix_time::ptime(boost::posix_time::pos_infin))
|
||||
{}
|
||||
|
||||
boost::asio::awaitable<void> async_wait() {
|
||||
try {
|
||||
co_await Deadline.async_wait(boost::asio::use_awaitable);
|
||||
} catch(boost::system::system_error code) {
|
||||
if(code.code() != boost::system::errc::operation_canceled)
|
||||
throw;
|
||||
}
|
||||
|
||||
co_await boost::asio::this_coro::throw_if_cancelled();
|
||||
void notify() {
|
||||
Timer.cancel();
|
||||
}
|
||||
|
||||
boost::asio::awaitable<void> async_wait(std::function<bool()> predicate) {
|
||||
while(!predicate())
|
||||
co_await async_wait();
|
||||
void wait() {
|
||||
Timer.wait();
|
||||
Timer.expires_at(boost::posix_time::ptime(boost::posix_time::pos_infin));
|
||||
}
|
||||
|
||||
coro<> async_wait() {
|
||||
try { co_await Timer.async_wait(); } catch(...) {}
|
||||
}
|
||||
|
||||
void notify_one() {
|
||||
Deadline.cancel_one();
|
||||
};
|
||||
|
||||
class WaitableCoro {
|
||||
asio::io_context &IOC;
|
||||
std::shared_ptr<MultipleToOne_AsyncSymaphore> Symaphore;
|
||||
std::exception_ptr LastException;
|
||||
|
||||
public:
|
||||
WaitableCoro(asio::io_context &ioc)
|
||||
: IOC(ioc)
|
||||
{}
|
||||
|
||||
template<typename Token>
|
||||
void co_spawn(Token token) {
|
||||
Symaphore = std::make_shared<MultipleToOne_AsyncSymaphore>(IOC);
|
||||
asio::co_spawn(IOC, [token = std::move(token), symaphore = Symaphore]() -> coro<> {
|
||||
co_await std::move(token);
|
||||
symaphore->notify();
|
||||
}, asio::detached);
|
||||
}
|
||||
|
||||
void notify_all() {
|
||||
Deadline.cancel();
|
||||
void wait() {
|
||||
Symaphore->wait();
|
||||
}
|
||||
|
||||
coro<> async_wait() {
|
||||
return Symaphore->async_wait();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Используется, чтобы вместо уничтожения объекта в умной ссылке, вызвать корутину с co_await asyncDestructor()
|
||||
*/
|
||||
class IAsyncDestructible : public std::enable_shared_from_this<IAsyncDestructible> {
|
||||
protected:
|
||||
boost::asio::any_io_executor IOC;
|
||||
boost::asio::deadline_timer DestructLine;
|
||||
asio::io_context &IOC;
|
||||
|
||||
virtual coro<> asyncDestructor() { DestructLine.cancel(); co_return; }
|
||||
virtual coro<> asyncDestructor() { co_return; }
|
||||
|
||||
public:
|
||||
IAsyncDestructible(boost::asio::any_io_executor ioc)
|
||||
: IOC(ioc), DestructLine(ioc, boost::posix_time::ptime(boost::posix_time::pos_infin))
|
||||
IAsyncDestructible(asio::io_context &ioc)
|
||||
: IOC(ioc)
|
||||
{}
|
||||
|
||||
virtual ~IAsyncDestructible() {}
|
||||
|
||||
coro<std::variant<std::monostate, std::monostate>> cancelable(coro<> &&c) { return std::move(c) || DestructLine.async_wait(boost::asio::use_awaitable); }
|
||||
|
||||
protected:
|
||||
template<typename T, typename = typename std::is_same<IAsyncDestructible, T>>
|
||||
static std::shared_ptr<T> createShared(boost::asio::any_io_executor ioc, T *ptr)
|
||||
static std::shared_ptr<T> createShared(asio::io_context &ioc, T *ptr)
|
||||
{
|
||||
return std::shared_ptr<T>(ptr, [ioc = std::move(ioc)](IAsyncDestructible *ptr) {
|
||||
return std::shared_ptr<T>(ptr, [&ioc = ioc](T *ptr) {
|
||||
boost::asio::co_spawn(ioc, [](IAsyncDestructible *ptr) -> coro<> {
|
||||
try { co_await ptr->asyncDestructor(); } catch(...) { }
|
||||
delete ptr;
|
||||
@@ -80,16 +139,40 @@ public:
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T, typename ...Args, typename = typename std::is_same<IAsyncDestructible, T>>
|
||||
static std::shared_ptr<T> makeShared(boost::asio::any_io_executor ioc, Args&& ... args)
|
||||
template<typename T, typename = typename std::is_same<IAsyncDestructible, T>>
|
||||
static coro<std::shared_ptr<T>> createShared(T *ptr)
|
||||
{
|
||||
std::shared_ptr<T>(new T(ioc, std::forward<Args>(args)..., [ioc = std::move(ioc)](IAsyncDestructible *ptr) {
|
||||
co_return std::shared_ptr<T>(ptr, [ioc = asio::get_associated_executor(co_await asio::this_coro::executor)](T *ptr) {
|
||||
boost::asio::co_spawn(ioc, [](IAsyncDestructible *ptr) -> coro<> {
|
||||
try { co_await ptr->asyncDestructor(); } catch(...) { }
|
||||
delete ptr;
|
||||
co_return;
|
||||
} (ptr), boost::asio::detached);
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T, typename = typename std::is_same<IAsyncDestructible, T>>
|
||||
static std::unique_ptr<T, std::function<void(T*)>> createUnique(asio::io_context &ioc, T *ptr)
|
||||
{
|
||||
return std::unique_ptr<T, std::function<void(T*)>>(ptr, [&ioc = ioc](T *ptr) {
|
||||
boost::asio::co_spawn(ioc, [](IAsyncDestructible *ptr) -> coro<> {
|
||||
try { co_await ptr->asyncDestructor(); } catch(...) { }
|
||||
delete ptr;
|
||||
co_return;
|
||||
} (ptr), boost::asio::detached);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T, typename = typename std::is_same<IAsyncDestructible, T>>
|
||||
static coro<std::unique_ptr<T, std::function<void(T*)>>> createUnique(T *ptr)
|
||||
{
|
||||
co_return std::unique_ptr<T, std::function<void(T*)>>(ptr, [ioc = asio::get_associated_executor(co_await asio::this_coro::executor)](T *ptr) {
|
||||
boost::asio::co_spawn(ioc, [](IAsyncDestructible *ptr) -> coro<> {
|
||||
try { co_await ptr->asyncDestructor(); } catch(...) { }
|
||||
delete ptr;
|
||||
co_return;
|
||||
} (ptr), boost::asio::detached);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user