Browse Source

完善when_all/when_any的文档。

删减一些不必要的宏。
tags/v2.9.7
tearshark 4 years ago
parent
commit
b6fa1c4e49

+ 1
- 0
librf/librf.h View File

#pragma once #pragma once
#include <cstddef>
#include <type_traits> #include <type_traits>
#include <atomic> #include <atomic>
#include <chrono> #include <chrono>

+ 1
- 1
librf/src/channel_v2.h View File

* 默认不是POD类型则采用std::optional<>。如果channel缓存的元素不能凭空产生,或者产生代价较大,则推荐将此参数设置为true,从而减小不必要的开销。 * 默认不是POD类型则采用std::optional<>。如果channel缓存的元素不能凭空产生,或者产生代价较大,则推荐将此参数设置为true,从而减小不必要的开销。
* @param _OptimizationThread 针对多线程优化。目前此算法提升效率不稳定,需要自行根据实际情况决定。 * @param _OptimizationThread 针对多线程优化。目前此算法提升效率不稳定,需要自行根据实际情况决定。
*/ */
template<class _Ty = bool, bool _Optional = !std::is_pod_v<_Ty>, bool _OptimizationThread = false>
template<class _Ty = bool, bool _Optional = !std::is_trivial_v<_Ty>, bool _OptimizationThread = false>
struct channel_t struct channel_t
{ {
static_assert((std::is_copy_constructible_v<_Ty>&& std::is_copy_assignable_v<_Ty>) || static_assert((std::is_copy_constructible_v<_Ty>&& std::is_copy_assignable_v<_Ty>) ||

+ 0
- 8
librf/src/macro_def.inl View File

#pragma once #pragma once


#ifndef _offset_of
#define _offset_of(c, m) reinterpret_cast<size_t>(&static_cast<c *>(0)->m)
#endif
#ifndef _countof
#define _countof(_Array) (sizeof(_Array)/sizeof((_Array)[0]))
#endif

#define co_yield_void co_yield nullptr #define co_yield_void co_yield nullptr
#define co_return_void co_return nullptr #define co_return_void co_return nullptr
#define resumf_guard_lock(lker) (lker).lock(); resumef::scoped_lock<resumef::mutex_t> __resumf_guard##lker##__(std::adopt_lock, (lker))


#if !defined(_DISABLE_RESUMEF_GO_MACRO) #if !defined(_DISABLE_RESUMEF_GO_MACRO)
#define go (*::resumef::this_scheduler()) + #define go (*::resumef::this_scheduler()) +

+ 1
- 1
librf/src/state.h View File

#ifndef __clang__ #ifndef __clang__
constexpr constexpr
#endif #endif
(_offset_of(state_future_t, _is_future) - _offset_of(state_future_t, _has_value) == 1)
(offsetof(state_future_t, _is_future) - offsetof(state_future_t, _has_value) == 1)
return 0 != reinterpret_cast<const std::atomic<uint16_t> &>(_has_value).load(std::memory_order_acquire); return 0 != reinterpret_cast<const std::atomic<uint16_t> &>(_has_value).load(std::memory_order_acquire);
else else
return _has_value.load(std::memory_order_acquire) != result_type::None || _is_future; return _has_value.load(std::memory_order_acquire) != result_type::None || _is_future;

+ 113
- 5
librf/src/when_v2.h View File

#ifndef DOXYGEN_SKIP_PROPERTY #ifndef DOXYGEN_SKIP_PROPERTY
inline namespace when_v2 inline namespace when_v2
{ {
#else
/**
* @brief 目前不知道怎么在doxygen里面能搜集到全局函数的文档。故用一个结构体来欺骗doxygen。
* @details 其下的所有成员函数,均是全局函数。
*/
struct when_{
#endif #endif


/**
* @brief 等待所有的可等待对象完成,不定参数版。
* @param sch 当前协程的调度器。
* @param args... 所有的可等待对象。要么是_AwaitableT<>类型,要么是返回_AwaitableT<>类型的函数(对象)。
* @retval [co_await] std::tuple<...>。每个可等待对象的返回值,逐个存入到std::tuple<...>里面。void 返回值,存的是std::ignore。
*/
template<_WhenTaskT... _Awaitable template<_WhenTaskT... _Awaitable
#ifndef DOXYGEN_SKIP_PROPERTY
COMMA_RESUMEF_ENABLE_IF(std::conjunction_v<detail::is_when_task<_Awaitable>...>) COMMA_RESUMEF_ENABLE_IF(std::conjunction_v<detail::is_when_task<_Awaitable>...>)
#endif //DOXYGEN_SKIP_PROPERTY
> >
auto when_all(scheduler_t& sch, _Awaitable&&... args) auto when_all(scheduler_t& sch, _Awaitable&&... args)
-> detail::when_future_t<std::tuple<detail::awaitor_result_t<_Awaitable>...> > -> detail::when_future_t<std::tuple<detail::awaitor_result_t<_Awaitable>...> >
return awaitor; return awaitor;
} }


/**
* @brief 等待所有的可等待对象完成,迭代器版。
* @param sch 当前协程的调度器。
* @param begin 可等待对象容器的起始迭代器。迭代器指向的,要么是_AwaitableT<>类型,要么是返回_AwaitableT<>类型的函数(对象)。
* @param end 可等待对象容器的结束迭代器。
* @retval [co_await] std::vector<>。每个可等待对象的返回值,逐个存入到std::vector<>里面。void 返回值,存的是std::ignore。
*/
template<_WhenIterT _Iter template<_WhenIterT _Iter
#ifndef DOXYGEN_SKIP_PROPERTY
COMMA_RESUMEF_ENABLE_IF(detail::is_when_task_iter_v<_Iter>) COMMA_RESUMEF_ENABLE_IF(detail::is_when_task_iter_v<_Iter>)
#endif //DOXYGEN_SKIP_PROPERTY
> >
auto when_all(scheduler_t& sch, _Iter begin, _Iter end) auto when_all(scheduler_t& sch, _Iter begin, _Iter end)
-> detail::when_future_t<std::vector<detail::awaitor_result_t<decltype(*std::declval<_Iter>())> > > -> detail::when_future_t<std::vector<detail::awaitor_result_t<decltype(*std::declval<_Iter>())> > >
return awaitor; return awaitor;
} }


/**
* @brief 等待所有的可等待对象完成,容器版。
* @param sch 当前协程的调度器。
* @param cont 存访可等待对象的容器。容器内存放的,要么是_AwaitableT<>类型,要么是返回_AwaitableT<>类型的函数(对象)。
* @retval [co_await] std::vector<>。每个可等待对象的返回值,逐个存入到std::vector<>里面。void 返回值,存的是std::ignore。
*/
template<_ContainerT _Cont template<_ContainerT _Cont
#ifndef DOXYGEN_SKIP_PROPERTY
COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>) COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>)
#endif //DOXYGEN_SKIP_PROPERTY
> >
decltype(auto) when_all(scheduler_t& sch, _Cont& cont) decltype(auto) when_all(scheduler_t& sch, _Cont& cont)
{ {
return when_all(sch, std::begin(cont), std::end(cont)); return when_all(sch, std::begin(cont), std::end(cont));
} }


/**
* @brief 等待所有的可等待对象完成,不定参数版。
* @details 当前协程的调度器通过current_scheduler()宏获得,与带调度器参数的版本相比,多一次resumeable function构造,效率可能低一点。
* @param args... 所有的可等待对象。要么是_AwaitableT<>类型,要么是返回_AwaitableT<>类型的函数(对象)。
* @retval [co_await] std::tuple<...>。每个可等待对象的返回值,逐个存入到std::tuple<...>里面。void 返回值,存的是std::ignore。
*/
template<_WhenTaskT... _Awaitable template<_WhenTaskT... _Awaitable
#ifndef DOXYGEN_SKIP_PROPERTY
COMMA_RESUMEF_ENABLE_IF(std::conjunction_v<detail::is_when_task<_Awaitable>...>) COMMA_RESUMEF_ENABLE_IF(std::conjunction_v<detail::is_when_task<_Awaitable>...>)
#endif //DOXYGEN_SKIP_PROPERTY
> >
auto when_all(_Awaitable&&... awaitor)
auto when_all(_Awaitable&&... args)
-> future_t<std::tuple<detail::awaitor_result_t<_Awaitable>...>> -> future_t<std::tuple<detail::awaitor_result_t<_Awaitable>...>>
{ {
scheduler_t* sch = current_scheduler(); scheduler_t* sch = current_scheduler();
co_return co_await when_all(*sch, std::forward<_Awaitable>(awaitor)...);
co_return co_await when_all(*sch, std::forward<_Awaitable>(args)...);
} }


/**
* @brief 等待所有的可等待对象完成,迭代器版。
* @details 当前协程的调度器通过current_scheduler()宏获得,与带调度器参数的版本相比,多一次resumeable function构造,效率可能低一点。
* @param begin 可等待对象容器的起始迭代器。迭代器指向的,要么是_AwaitableT<>类型,要么是返回_AwaitableT<>类型的函数(对象)。
* @param end 可等待对象容器的结束迭代器。
* @retval [co_await] std::vector<>。每个可等待对象的返回值,逐个存入到std::vector<>里面。void 返回值,存的是std::ignore。
*/
template<_WhenIterT _Iter template<_WhenIterT _Iter
#ifndef DOXYGEN_SKIP_PROPERTY
COMMA_RESUMEF_ENABLE_IF(detail::is_when_task_iter_v<_Iter>) COMMA_RESUMEF_ENABLE_IF(detail::is_when_task_iter_v<_Iter>)
#endif //DOXYGEN_SKIP_PROPERTY
> >
auto when_all(_Iter begin, _Iter end) auto when_all(_Iter begin, _Iter end)
-> future_t<std::vector<detail::awaitor_result_t<decltype(*begin)>>> -> future_t<std::vector<detail::awaitor_result_t<decltype(*begin)>>>
co_return co_await when_all(*sch, begin, end); co_return co_await when_all(*sch, begin, end);
} }


/**
* @brief 等待所有的可等待对象完成,容器版。
* @details 当前协程的调度器通过current_scheduler()宏获得,与带调度器参数的版本相比,多一次resumeable function构造,效率可能低一点。
* @param cont 存访可等待对象的容器。容器内存放的,要么是_AwaitableT<>类型,要么是返回_AwaitableT<>类型的函数(对象)。
* @retval [co_await] std::vector<>。每个可等待对象的返回值,逐个存入到std::vector<>里面。void 返回值,存的是std::ignore。
*/
template<_ContainerT _Cont template<_ContainerT _Cont
#ifndef DOXYGEN_SKIP_PROPERTY
COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>) COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>)
#endif //DOXYGEN_SKIP_PROPERTY
> >
auto when_all(_Cont&& cont) auto when_all(_Cont&& cont)
-> future_t<std::vector<detail::awaitor_result_t<decltype(*std::begin(cont))>>> -> future_t<std::vector<detail::awaitor_result_t<decltype(*std::begin(cont))>>>






/**
* @brief 等待任一的可等待对象完成,不定参数版。
* @param sch 当前协程的调度器。
* @param args... 所有的可等待对象。要么是_AwaitableT<>类型,要么是返回_AwaitableT<>类型的函数(对象)。
* @retval [co_await] std::pair<intptr_t, std::any>。第一个值指示哪个对象完成了,第二个值存访的对应的返回数据。
*/
template<_WhenTaskT... _Awaitable template<_WhenTaskT... _Awaitable
#ifndef DOXYGEN_SKIP_PROPERTY
COMMA_RESUMEF_ENABLE_IF(std::conjunction_v<detail::is_when_task<_Awaitable>...>) COMMA_RESUMEF_ENABLE_IF(std::conjunction_v<detail::is_when_task<_Awaitable>...>)
#endif //DOXYGEN_SKIP_PROPERTY
> >
auto when_any(scheduler_t& sch, _Awaitable&&... args) auto when_any(scheduler_t& sch, _Awaitable&&... args)
-> detail::when_future_t<when_any_pair> -> detail::when_future_t<when_any_pair>
return awaitor; return awaitor;
} }


/**
* @brief 等待任一的可等待对象完成,迭代器版。
* @param sch 当前协程的调度器。
* @param begin 可等待对象容器的起始迭代器。迭代器指向的,要么是_AwaitableT<>类型,要么是返回_AwaitableT<>类型的函数(对象)。
* @param end 可等待对象容器的结束迭代器。
* @retval [co_await] std::pair<intptr_t, std::any>。第一个值指示哪个对象完成了,第二个值存访的对应的返回数据。
*/
template<_WhenIterT _Iter template<_WhenIterT _Iter
#ifndef DOXYGEN_SKIP_PROPERTY
COMMA_RESUMEF_ENABLE_IF(detail::is_when_task_iter_v<_Iter>) COMMA_RESUMEF_ENABLE_IF(detail::is_when_task_iter_v<_Iter>)
#endif //DOXYGEN_SKIP_PROPERTY
> >
auto when_any(scheduler_t& sch, _Iter begin, _Iter end) auto when_any(scheduler_t& sch, _Iter begin, _Iter end)
-> detail::when_future_t<when_any_pair> -> detail::when_future_t<when_any_pair>
return awaitor; return awaitor;
} }


/**
* @brief 等待任一的可等待对象完成,容器版。
* @param sch 当前协程的调度器。
* @param cont 存访可等待对象的容器。容器内存放的,要么是_AwaitableT<>类型,要么是返回_AwaitableT<>类型的函数(对象)。
* @retval [co_await] std::pair<intptr_t, std::any>。第一个值指示哪个对象完成了,第二个值存访的对应的返回数据。
*/
template<_ContainerT _Cont template<_ContainerT _Cont
#ifndef DOXYGEN_SKIP_PROPERTY
COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>) COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>)
#endif //DOXYGEN_SKIP_PROPERTY
> >
decltype(auto) when_any(scheduler_t& sch, _Cont& cont)
auto when_any(scheduler_t& sch, _Cont& cont)
-> detail::when_future_t<when_any_pair>
{ {
return when_any(sch, std::begin(cont), std::end(cont)); return when_any(sch, std::begin(cont), std::end(cont));
} }


/**
* @brief 等待任一的可等待对象完成,不定参数版。
* @details 当前协程的调度器通过current_scheduler()宏获得,与带调度器参数的版本相比,多一次resumeable function构造,效率可能低一点。
* @param args... 所有的可等待对象。要么是_AwaitableT<>类型,要么是返回_AwaitableT<>类型的函数(对象)。
* @retval [co_await] std::pair<intptr_t, std::any>。第一个值指示哪个对象完成了,第二个值存访的对应的返回数据。
*/
template<_WhenTaskT... _Awaitable template<_WhenTaskT... _Awaitable
#ifndef DOXYGEN_SKIP_PROPERTY
COMMA_RESUMEF_ENABLE_IF(std::conjunction_v<detail::is_when_task<_Awaitable>...>) COMMA_RESUMEF_ENABLE_IF(std::conjunction_v<detail::is_when_task<_Awaitable>...>)
#endif //DOXYGEN_SKIP_PROPERTY
> >
auto when_any(_Awaitable&&... awaitor)
auto when_any(_Awaitable&&... args)
-> future_t<when_any_pair> -> future_t<when_any_pair>
{ {
scheduler_t* sch = current_scheduler(); scheduler_t* sch = current_scheduler();
co_return co_await when_any(*sch, std::forward<_Awaitable>(awaitor)...);
co_return co_await when_any(*sch, std::forward<_Awaitable>(args)...);
} }


/**
* @brief 等待任一的可等待对象完成,迭代器版。
* @details 当前协程的调度器通过current_scheduler()宏获得,与带调度器参数的版本相比,多一次resumeable function构造,效率可能低一点。
* @param begin 可等待对象容器的起始迭代器。迭代器指向的,要么是_AwaitableT<>类型,要么是返回_AwaitableT<>类型的函数(对象)。
* @param end 可等待对象容器的结束迭代器。
* @retval [co_await] std::pair<intptr_t, std::any>。第一个值指示哪个对象完成了,第二个值存访的对应的返回数据。
*/
template<_WhenIterT _Iter template<_WhenIterT _Iter
#ifndef DOXYGEN_SKIP_PROPERTY
COMMA_RESUMEF_ENABLE_IF(detail::is_when_task_iter_v<_Iter>) COMMA_RESUMEF_ENABLE_IF(detail::is_when_task_iter_v<_Iter>)
#endif //DOXYGEN_SKIP_PROPERTY
> >
auto when_any(_Iter begin, _Iter end) auto when_any(_Iter begin, _Iter end)
-> future_t<when_any_pair> -> future_t<when_any_pair>
co_return co_await when_any(*sch, begin, end); co_return co_await when_any(*sch, begin, end);
} }


/**
* @brief 等待任一的可等待对象完成,容器版。
* @details 当前协程的调度器通过current_scheduler()宏获得,与带调度器参数的版本相比,多一次resumeable function构造,效率可能低一点。
* @param cont 存访可等待对象的容器。容器内存放的,要么是_AwaitableT<>类型,要么是返回_AwaitableT<>类型的函数(对象)。
* @retval [co_await] std::pair<intptr_t, std::any>。第一个值指示哪个对象完成了,第二个值存访的对应的返回数据。
*/
template<_ContainerT _Cont template<_ContainerT _Cont
#ifndef DOXYGEN_SKIP_PROPERTY
COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>) COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>)
#endif //DOXYGEN_SKIP_PROPERTY
> >
auto when_any(_Cont&& cont) auto when_any(_Cont&& cont)
-> future_t<when_any_pair>
{ {
return when_any(std::begin(cont), std::end(cont)); return when_any(std::begin(cont), std::end(cont));
} }

+ 1
- 1
tutorial/test_async_event.cpp View File

go[&]() -> future_t<> go[&]() -> future_t<>
{ {
for (size_t i = 0; i < _countof(evts); ++i)
for (size_t i = 0; i < std::size(evts); ++i)
{ {
intptr_t idx = co_await event_t::wait_any(evts); intptr_t idx = co_await event_t::wait_any(evts);
std::cout << "event " << idx << " signal!" << std::endl; std::cout << "event " << idx << " signal!" << std::endl;

+ 1
- 1
tutorial/test_async_event_v2.cpp View File

event_v2::event_t evts[10]; event_v2::event_t evts[10];


std::vector<std::thread> vtt; std::vector<std::thread> vtt;
for(size_t i = 0; i < _countof(evts); ++i)
for(size_t i = 0; i < std::size(evts); ++i)
{ {
go resumable_wait_timeout(evts[i], 100ms, (int)i); go resumable_wait_timeout(evts[i], 100ms, (int)i);
vtt.emplace_back(async_set_event_one(evts[i], 1ms * (50 + i * 10))); vtt.emplace_back(async_set_event_one(evts[i], 1ms * (50 + i * 10)));

+ 1
- 1
tutorial/test_async_resumable.cpp View File

/* /*
std::thread works[32]; std::thread works[32];
for (size_t w = 1; w <= _countof(works); ++w)
for (size_t w = 1; w <= std::size(works); ++w)
{ {
for (size_t idx = 0; idx < w; ++idx) for (size_t idx = 0; idx < w; ++idx)
works[idx] = std::thread(&resumable_switch, 1000, idx); works[idx] = std::thread(&resumable_switch, 1000, idx);

+ 1
- 1
tutorial/test_async_sleep.cpp View File

}; };
srand((int)time(nullptr)); srand((int)time(nullptr));
for (size_t i = 0; i < _countof(evts); ++i)
for (size_t i = 0; i < std::size(evts); ++i)
{ {
go[&, i]() -> future_t<> go[&, i]() -> future_t<>
{ {

Loading…
Cancel
Save