Browse Source

完善when_all/when_any的文档。

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

+ 1
- 0
librf/librf.h View File

@@ -16,6 +16,7 @@
#pragma once
#include <cstddef>
#include <type_traits>
#include <atomic>
#include <chrono>

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

@@ -21,7 +21,7 @@ inline namespace channel_v2
* 默认不是POD类型则采用std::optional<>。如果channel缓存的元素不能凭空产生,或者产生代价较大,则推荐将此参数设置为true,从而减小不必要的开销。
* @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
{
static_assert((std::is_copy_constructible_v<_Ty>&& std::is_copy_assignable_v<_Ty>) ||

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

@@ -1,15 +1,7 @@
#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_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)
#define go (*::resumef::this_scheduler()) +

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

@@ -153,7 +153,7 @@ namespace resumef
#ifndef __clang__
constexpr
#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);
else
return _has_value.load(std::memory_order_acquire) != result_type::None || _is_future;

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

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

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

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

/**
* @brief 等待所有的可等待对象完成,容器版。
* @param sch 当前协程的调度器。
* @param cont 存访可等待对象的容器。容器内存放的,要么是_AwaitableT<>类型,要么是返回_AwaitableT<>类型的函数(对象)。
* @retval [co_await] std::vector<>。每个可等待对象的返回值,逐个存入到std::vector<>里面。void 返回值,存的是std::ignore。
*/
template<_ContainerT _Cont
#ifndef DOXYGEN_SKIP_PROPERTY
COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>)
#endif //DOXYGEN_SKIP_PROPERTY
>
decltype(auto) when_all(scheduler_t& sch, _Cont& 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
#ifndef DOXYGEN_SKIP_PROPERTY
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>...>>
{
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
#ifndef DOXYGEN_SKIP_PROPERTY
COMMA_RESUMEF_ENABLE_IF(detail::is_when_task_iter_v<_Iter>)
#endif //DOXYGEN_SKIP_PROPERTY
>
auto when_all(_Iter begin, _Iter end)
-> future_t<std::vector<detail::awaitor_result_t<decltype(*begin)>>>
@@ -314,8 +362,16 @@ inline namespace when_v2
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
#ifndef DOXYGEN_SKIP_PROPERTY
COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>)
#endif //DOXYGEN_SKIP_PROPERTY
>
auto when_all(_Cont&& cont)
-> future_t<std::vector<detail::awaitor_result_t<decltype(*std::begin(cont))>>>
@@ -325,8 +381,16 @@ inline namespace when_v2



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

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

/**
* @brief 等待任一的可等待对象完成,容器版。
* @param sch 当前协程的调度器。
* @param cont 存访可等待对象的容器。容器内存放的,要么是_AwaitableT<>类型,要么是返回_AwaitableT<>类型的函数(对象)。
* @retval [co_await] std::pair<intptr_t, std::any>。第一个值指示哪个对象完成了,第二个值存访的对应的返回数据。
*/
template<_ContainerT _Cont
#ifndef DOXYGEN_SKIP_PROPERTY
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));
}

/**
* @brief 等待任一的可等待对象完成,不定参数版。
* @details 当前协程的调度器通过current_scheduler()宏获得,与带调度器参数的版本相比,多一次resumeable function构造,效率可能低一点。
* @param args... 所有的可等待对象。要么是_AwaitableT<>类型,要么是返回_AwaitableT<>类型的函数(对象)。
* @retval [co_await] std::pair<intptr_t, std::any>。第一个值指示哪个对象完成了,第二个值存访的对应的返回数据。
*/
template<_WhenTaskT... _Awaitable
#ifndef DOXYGEN_SKIP_PROPERTY
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>
{
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
#ifndef DOXYGEN_SKIP_PROPERTY
COMMA_RESUMEF_ENABLE_IF(detail::is_when_task_iter_v<_Iter>)
#endif //DOXYGEN_SKIP_PROPERTY
>
auto when_any(_Iter begin, _Iter end)
-> future_t<when_any_pair>
@@ -381,10 +480,19 @@ inline namespace when_v2
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
#ifndef DOXYGEN_SKIP_PROPERTY
COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>)
#endif //DOXYGEN_SKIP_PROPERTY
>
auto when_any(_Cont&& cont)
-> future_t<when_any_pair>
{
return when_any(std::begin(cont), std::end(cont));
}

+ 1
- 1
tutorial/test_async_event.cpp View File

@@ -96,7 +96,7 @@ static void test_wait_any()
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);
std::cout << "event " << idx << " signal!" << std::endl;

+ 1
- 1
tutorial/test_async_event_v2.cpp View File

@@ -86,7 +86,7 @@ static void test_wait_all_timeout()
event_v2::event_t evts[10];

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);
vtt.emplace_back(async_set_event_one(evts[i], 1ms * (50 + i * 10)));

+ 1
- 1
tutorial/test_async_resumable.cpp View File

@@ -64,7 +64,7 @@ void resumable_main_resumable()
/*
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)
works[idx] = std::thread(&resumable_switch, 1000, idx);

+ 1
- 1
tutorial/test_async_sleep.cpp View File

@@ -45,7 +45,7 @@ void test_wait_all_events_with_signal_by_sleep()
};
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<>
{

Loading…
Cancel
Save