cmake_minimum_required(VERSION 3.14) | |||||
PROJECT(librf) | |||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") | |||||
set(CMAKE_CXX_FLAGS "-std=c++2a -fcoroutines-ts -stdlib=libc++") | |||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") | |||||
set(CMAKE_CXX_FLAGS "-std=c++2a -fcoroutines-ts") | |||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") | |||||
set(CMAKE_CXX_FLAGS "/std:c++latest /await /EHsc") | |||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") | |||||
set(CMAKE_CXX_FLAGS "-std=c++2a -fcoroutines-ts") | |||||
endif() | |||||
message(STATUS "C++ flags: ${CMAKE_CXX_FLAGS}") | |||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") | |||||
option(OPT_INLINE_STATE "Enable Inline state" ON) | |||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") | |||||
option(OPT_INLINE_STATE "Enable Inline state" ON) | |||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") | |||||
option(OPT_INLINE_STATE "Enable Inline state" ON) | |||||
else() | |||||
option(OPT_INLINE_STATE "Enable Inline state" OFF) | |||||
endif() | |||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") | |||||
option(OPT_USE_CONCEPT "Use conecpt instead of enable_if" ON) | |||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") | |||||
option(OPT_USE_CONCEPT "Use conecpt instead of enable_if" ON) | |||||
else() | |||||
option(OPT_USE_CONCEPT "Use conecpt instead of enable_if" OFF) | |||||
endif() | |||||
option(OPT_DEBUG_COUNTER "Debug objects count" OFF) | |||||
option(OPT_KEEP_REAL_SIZE "Keep real size in queue" OFF) | |||||
#set(RESUMEF_USE_CUSTOM_SPINLOCK "std::mutex") | |||||
if(OPT_INLINE_STATE) | |||||
set(RESUMEF_INLINE_STATE 1) | |||||
endif() | |||||
if(OPT_DEBUG_COUNTER) | |||||
set(RESUMEF_DEBUG_COUNTER 1) | |||||
endif() | |||||
if(OPT_USE_CONCEPT) | |||||
set(RESUMEF_ENABLE_CONCEPT 1) | |||||
endif() | |||||
if(OPT_KEEP_REAL_SIZE) | |||||
set(_WITH_LOCK_FREE_Q_KEEP_REAL_SIZE 1) | |||||
endif() | |||||
configure_file( | |||||
${PROJECT_SOURCE_DIR}/config.h.in | |||||
${PROJECT_SOURCE_DIR}/librf/src/config.h) | |||||
include_directories( | |||||
${PROJECT_SOURCE_DIR}/librf | |||||
) | |||||
set(SRC | |||||
${PROJECT_SOURCE_DIR}/librf/src/event_v1.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/event_v2.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/mutex_v1.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/mutex_v2.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/rf_task.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/scheduler.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/sleep.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/state.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/timer.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/when_v2.cpp | |||||
) | |||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib) | |||||
set(LIB_NAME librf) | |||||
#add_library(${LIB_NAME} SHARED ${SRC}) | |||||
add_library(${LIB_NAME} STATIC ${SRC}) | |||||
include_directories( | |||||
${PROJECT_SOURCE_DIR}/modern_cb | |||||
) | |||||
aux_source_directory(${PROJECT_SOURCE_DIR}/tutorial TSRC) | |||||
set(TSRC ${TSRC} | |||||
${PROJECT_SOURCE_DIR}/benchmark/benchmark_async_mem.cpp | |||||
${PROJECT_SOURCE_DIR}/benchmark/benchmark_channel_passing_next.cpp | |||||
${PROJECT_SOURCE_DIR}/test_librf.cpp | |||||
) | |||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin) | |||||
add_executable(test ${TSRC}) | |||||
target_link_libraries(test ${LIB_NAME}) | |||||
cmake_minimum_required(VERSION 3.10) | |||||
project(librf) | |||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") | |||||
set(CMAKE_CXX_FLAGS "-std=c++2a -fcoroutines-ts -stdlib=libc++") | |||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") | |||||
set(CMAKE_CXX_FLAGS "-std=c++2a -fcoroutines-ts") | |||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") | |||||
set(CMAKE_CXX_FLAGS "/std:c++latest /await /EHsc") | |||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") | |||||
set(CMAKE_CXX_FLAGS "-std=c++2a -fcoroutines -pthread") | |||||
endif() | |||||
message(STATUS "C++ flags: ${CMAKE_CXX_FLAGS}") | |||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") | |||||
option(OPT_INLINE_STATE "Enable Inline state" ON) | |||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") | |||||
option(OPT_INLINE_STATE "Enable Inline state" ON) | |||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") | |||||
option(OPT_INLINE_STATE "Enable Inline state" ON) | |||||
else() | |||||
option(OPT_INLINE_STATE "Enable Inline state" OFF) | |||||
endif() | |||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") | |||||
option(OPT_USE_CONCEPT "Use conecpt instead of enable_if" ON) | |||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") | |||||
option(OPT_USE_CONCEPT "Use conecpt instead of enable_if" OFF) | |||||
else() | |||||
option(OPT_USE_CONCEPT "Use conecpt instead of enable_if" OFF) | |||||
endif() | |||||
option(OPT_DEBUG_COUNTER "Debug objects count" OFF) | |||||
option(OPT_KEEP_REAL_SIZE "Keep real size in queue" OFF) | |||||
#set(RESUMEF_USE_CUSTOM_SPINLOCK "std::mutex") | |||||
if(OPT_INLINE_STATE) | |||||
set(RESUMEF_INLINE_STATE 1) | |||||
endif() | |||||
if(OPT_DEBUG_COUNTER) | |||||
set(RESUMEF_DEBUG_COUNTER 1) | |||||
endif() | |||||
if(OPT_USE_CONCEPT) | |||||
set(RESUMEF_ENABLE_CONCEPT 1) | |||||
endif() | |||||
if(OPT_KEEP_REAL_SIZE) | |||||
set(_WITH_LOCK_FREE_Q_KEEP_REAL_SIZE 1) | |||||
endif() | |||||
configure_file( | |||||
${PROJECT_SOURCE_DIR}/config.h.in | |||||
${PROJECT_SOURCE_DIR}/librf/src/config.h) | |||||
include_directories( | |||||
${PROJECT_SOURCE_DIR}/librf | |||||
) | |||||
set(SRC | |||||
${PROJECT_SOURCE_DIR}/librf/src/event_v1.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/event_v2.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/mutex_v1.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/mutex_v2.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/rf_task.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/scheduler.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/sleep.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/state.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/timer.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/when_v2.cpp | |||||
) | |||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib) | |||||
set(LIB_NAME librf) | |||||
#add_library(${LIB_NAME} SHARED ${SRC}) | |||||
add_library(${LIB_NAME} STATIC ${SRC}) | |||||
include_directories( | |||||
${PROJECT_SOURCE_DIR}/modern_cb | |||||
) | |||||
aux_source_directory(${PROJECT_SOURCE_DIR}/tutorial TSRC) | |||||
set(TSRC ${TSRC} | |||||
${PROJECT_SOURCE_DIR}/benchmark/benchmark_async_mem.cpp | |||||
${PROJECT_SOURCE_DIR}/benchmark/benchmark_channel_passing_next.cpp | |||||
${PROJECT_SOURCE_DIR}/test_librf.cpp | |||||
) | |||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin) | |||||
add_executable(rf_tutorial ${TSRC}) | |||||
target_link_libraries(rf_tutorial ${LIB_NAME}) |
const size_t N = 2000000; | const size_t N = 2000000; | ||||
const size_t LOOP_COUNT = 50; | const size_t LOOP_COUNT = 50; | ||||
volatile size_t globalValue = 0; | |||||
std::atomic<size_t> globalValue{0}; | |||||
void resumable_main_benchmark_mem(bool wait_key) | void resumable_main_benchmark_mem(bool wait_key) | ||||
{ | { |
} | } | ||||
} | } | ||||
static future_t<> passing_loop_all(channel_t<intptr_t> head, channel_t<intptr_t> tail) | |||||
{ | |||||
for (int i = 0; i < LoopCount; ++i) | |||||
{ | |||||
auto tstart = high_resolution_clock::now(); | |||||
co_await(head << 0); | |||||
intptr_t value = co_await tail; | |||||
auto dt = duration_cast<duration<double>>(high_resolution_clock::now() - tstart).count(); | |||||
std::cout << value << " cost time " << dt << "s" << std::endl; | |||||
} | |||||
} | |||||
void benchmark_main_channel_passing_next() | void benchmark_main_channel_passing_next() | ||||
{ | { | ||||
channel_t<intptr_t> head{1}; | channel_t<intptr_t> head{1}; | ||||
in = tail; | in = tail; | ||||
} | } | ||||
#if defined(__GNUC__) | |||||
go passing_loop_all(head, tail); | |||||
#else | |||||
GO | GO | ||||
{ | { | ||||
for (int i = 0; i < LoopCount; ++i) | for (int i = 0; i < LoopCount; ++i) | ||||
std::cout << value << " cost time " << dt << "s" << std::endl; | std::cout << value << " cost time " << dt << "s" << std::endl; | ||||
} | } | ||||
}; | }; | ||||
#endif | |||||
this_scheduler()->run_until_notask(); | this_scheduler()->run_until_notask(); | ||||
} | } |
#include <thread> | #include <thread> | ||||
#include <iostream> | #include <iostream> | ||||
#include <assert.h> | #include <assert.h> | ||||
#if defined(__clang__) | |||||
#if defined(__clang__) || defined(__GNUC__) | |||||
#include "src/unix/coroutine.h" //编译器内建的协程函数,MSVC和clang不一样 | #include "src/unix/coroutine.h" //编译器内建的协程函数,MSVC和clang不一样 | ||||
#else | #else | ||||
#include <experimental/coroutine> | #include <experimental/coroutine> |
#pragma once | |||||
#ifndef RESUMEF_INLINE_STATE | |||||
#if defined(__clang__) || defined(_MSC_VER) | |||||
#define RESUMEF_INLINE_STATE 1 | |||||
#else | |||||
#define RESUMEF_INLINE_STATE 1 | |||||
#endif //defined(__clang__) || defined(_MSC_VER) | |||||
#endif //RESUMEF_INLINE_STATE | |||||
#ifndef RESUMEF_DEBUG_COUNTER | |||||
/* #undef RESUMEF_DEBUG_COUNTER */ | |||||
#endif //RESUMEF_DEBUG_COUNTER | |||||
#ifndef RESUMEF_ENABLE_CONCEPT | |||||
#ifdef __cpp_lib_concepts | |||||
#define RESUMEF_ENABLE_CONCEPT 0 | |||||
#else | |||||
#define RESUMEF_ENABLE_CONCEPT 0 | |||||
#endif //#ifdef __cpp_lib_concepts | |||||
#endif //#ifndef RESUMEF_ENABLE_CONCEPT | |||||
#ifndef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE | |||||
/* #undef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE */ | |||||
#endif //_WITH_LOCK_FREE_Q_KEEP_REAL_SIZE | |||||
/* #undef RESUMEF_USE_CUSTOM_SPINLOCK */ | |||||
#pragma once | |||||
#ifndef RESUMEF_INLINE_STATE | |||||
#if defined(__clang__) || defined(_MSC_VER) | |||||
/* #undef RESUMEF_INLINE_STATE */ | |||||
#else | |||||
/* #undef RESUMEF_INLINE_STATE */ | |||||
#endif //defined(__clang__) || defined(_MSC_VER) | |||||
#endif //RESUMEF_INLINE_STATE | |||||
#ifndef RESUMEF_DEBUG_COUNTER | |||||
/* #undef RESUMEF_DEBUG_COUNTER */ | |||||
#endif //RESUMEF_DEBUG_COUNTER | |||||
#ifndef RESUMEF_ENABLE_CONCEPT | |||||
#ifdef __cpp_lib_concepts | |||||
/* #undef RESUMEF_ENABLE_CONCEPT */ | |||||
#else | |||||
/* #undef RESUMEF_ENABLE_CONCEPT */ | |||||
#endif //#ifdef __cpp_lib_concepts | |||||
#endif //#ifndef RESUMEF_ENABLE_CONCEPT | |||||
#ifndef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE | |||||
/* #undef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE */ | |||||
#endif //_WITH_LOCK_FREE_Q_KEEP_REAL_SIZE | |||||
/* #undef RESUMEF_USE_CUSTOM_SPINLOCK */ |
(void)e; | (void)e; | ||||
std::terminate(); | std::terminate(); | ||||
} | } | ||||
#ifdef __clang__ | |||||
#if defined(__clang__) || defined(__GNUC__) | |||||
void unhandled_exception() | void unhandled_exception() | ||||
{ | { | ||||
std::terminate(); | std::terminate(); |
* @brief 在析构的时候自动解锁mutex_t的辅助类。 | * @brief 在析构的时候自动解锁mutex_t的辅助类。 | ||||
*/ | */ | ||||
template<class... _Mtxs> | template<class... _Mtxs> | ||||
struct [[nodiscard]] batch_unlock_t; | |||||
struct batch_unlock_t; | |||||
/** | /** | ||||
* @brief 支持递归的锁。 | * @brief 支持递归的锁。 |
for (int cnt = rand() % (1 + _mutex.size()); cnt >= 0; --cnt) | for (int cnt = rand() % (1 + _mutex.size()); cnt >= 0; --cnt) | ||||
{ | { | ||||
std::this_thread::yield(); //还要考虑多线程里运行的情况 | std::this_thread::yield(); //还要考虑多线程里运行的情况 | ||||
co_await ::resumef::yield(); | |||||
co_await yield_awaitor{}; | |||||
} | } | ||||
} | } | ||||
future_t<> _ReturnValue() const; | future_t<> _ReturnValue() const; | ||||
}; | }; | ||||
template<class... _Mtxs> | template<class... _Mtxs> | ||||
struct [[nodiscard]] batch_unlock_t | |||||
struct batch_unlock_t | |||||
{ | { | ||||
mutex_t::_MutexAwaitAssembleT _MAA; | mutex_t::_MutexAwaitAssembleT _MAA; | ||||
co_return std::move(unlock_guard); | co_return std::move(unlock_guard); | ||||
} | } | ||||
#ifndef __GNUC__ | |||||
template<class... _Mtxs, typename> | template<class... _Mtxs, typename> | ||||
inline future_t<> mutex_t::lock(adopt_manual_unlock_t, _Mtxs&... mtxs) | inline future_t<> mutex_t::lock(adopt_manual_unlock_t, _Mtxs&... mtxs) | ||||
{ | { | ||||
mutex_t::_MutexAwaitAssembleT _MAA{ root_state(), mtxs... }; | mutex_t::_MutexAwaitAssembleT _MAA{ root_state(), mtxs... }; | ||||
co_await detail::mutex_lock_await_lock_impl::_Lock_range(_MAA); | co_await detail::mutex_lock_await_lock_impl::_Lock_range(_MAA); | ||||
} | } | ||||
#endif | |||||
template<class... _Mtxs, typename> | template<class... _Mtxs, typename> | ||||
inline future_t<> mutex_t::unlock(_Mtxs&... mtxs) | inline future_t<> mutex_t::unlock(_Mtxs&... mtxs) | ||||
{ | { |
template <typename _Uty> | template <typename _Uty> | ||||
_Uty&& await_transform(_Uty&& _Whatever) noexcept; | _Uty&& await_transform(_Uty&& _Whatever) noexcept; | ||||
void set_exception(std::exception_ptr e); | void set_exception(std::exception_ptr e); | ||||
#ifdef __clang__ | |||||
#if defined(__clang__) || defined(__GNUC__) | |||||
void unhandled_exception(); //If the coroutine ends with an uncaught exception, it performs the following: | void unhandled_exception(); //If the coroutine ends with an uncaught exception, it performs the following: | ||||
#endif | #endif | ||||
future_type get_return_object() noexcept; | future_type get_return_object() noexcept; |
this->get_state()->set_exception(std::move(e)); | this->get_state()->set_exception(std::move(e)); | ||||
} | } | ||||
#ifdef __clang__ | |||||
#if defined(__clang__) || defined(__GNUC__) | |||||
template <typename _Ty> | template <typename _Ty> | ||||
inline void promise_impl_t<_Ty>::unhandled_exception() | inline void promise_impl_t<_Ty>::unhandled_exception() | ||||
{ | { |
{ | { | ||||
if (classname) | if (classname) | ||||
{ | { | ||||
#if __clang__ | |||||
#if defined(__clang__) || defined(__GNUC__) | |||||
#define sprintf_s sprintf | #define sprintf_s sprintf | ||||
#endif | #endif | ||||
sprintf_s(sz_future_error_buffer, "%s, code=%s", classname, future_error_string[(size_t)(fe)]); | sprintf_s(sz_future_error_buffer, "%s, code=%s", classname, future_error_string[(size_t)(fe)]); |
//msvc认为是constexpr表达式(不写还给警告),然而,clang不这么认为。 | //msvc认为是constexpr表达式(不写还给警告),然而,clang不这么认为。 | ||||
//放弃constexpr,反正合格的编译器都会优化掉这个if判断的。 | //放弃constexpr,反正合格的编译器都会优化掉这个if判断的。 | ||||
if | if | ||||
#ifndef __clang__ | |||||
#ifdef _MSC_VER | |||||
constexpr | constexpr | ||||
#endif | #endif | ||||
(_offset_of(state_future_t, _is_future) - _offset_of(state_future_t, _has_value) == 1) | (_offset_of(state_future_t, _is_future) - _offset_of(state_future_t, _has_value) == 1) |
#include <memory> // for hash<T*> | #include <memory> // for hash<T*> | ||||
#include <cstddef> | #include <cstddef> | ||||
#include <cassert> | #include <cassert> | ||||
#if defined(__clang__) | |||||
#include "clang_builtin.h" | #include "clang_builtin.h" | ||||
#elif defined(__GNUC__) | |||||
#include "gcc_builtin.h" | |||||
#endif | |||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||||
#pragma GCC system_header | #pragma GCC system_header | ||||
#ifndef _LIBCPP_HAS_NO_COROUTINES | #ifndef _LIBCPP_HAS_NO_COROUTINES | ||||
namespace std { | namespace std { | ||||
#if defined(__GNUC__) | |||||
inline | |||||
#endif | |||||
namespace experimental { | namespace experimental { | ||||
template <class _Tp, class = void> | template <class _Tp, class = void> |
try { | try { | ||||
for (; _Next != _Last; ++_Next) | for (; _Next != _Last; ++_Next) | ||||
{ | { | ||||
if (!LOCK_ASSEMBLE_AWAIT(_LkN._Try_lock_ref(_LkN[_Next]))) | |||||
auto _Result__ = LOCK_ASSEMBLE_AWAIT(_LkN._Try_lock_ref(_LkN[_Next])); | |||||
if (!_Result__) | |||||
{ // try_lock failed, backout | { // try_lock failed, backout | ||||
_Unlock_locks(_First, _Next, _LkN); | _Unlock_locks(_First, _Next, _LkN); | ||||
LOCK_ASSEMBLE_RETURN(_Next); | LOCK_ASSEMBLE_RETURN(_Next); | ||||
// attempt to lock 2 locks, by first locking _Lk0, and then trying to lock _Lk1 returns whether to try again | // attempt to lock 2 locks, by first locking _Lk0, and then trying to lock _Lk1 returns whether to try again | ||||
LOCK_ASSEMBLE_AWAIT(_LkN._Lock_ref(_LkN[_Idx0])); | LOCK_ASSEMBLE_AWAIT(_LkN._Lock_ref(_LkN[_Idx0])); | ||||
try { | try { | ||||
if (LOCK_ASSEMBLE_AWAIT(_LkN._Try_lock_ref(_LkN[_Idx1]))) | |||||
auto _Result__ = LOCK_ASSEMBLE_AWAIT(_LkN._Try_lock_ref(_LkN[_Idx1])); | |||||
if (_Result__) | |||||
LOCK_ASSEMBLE_RETURN(false); | LOCK_ASSEMBLE_RETURN(false); | ||||
} | } | ||||
catch (...) { | catch (...) { | ||||
static auto _Lock_nonmember2(_LA& _LkN) ->decltype(_LkN._ReturnValue()) | static auto _Lock_nonmember2(_LA& _LkN) ->decltype(_LkN._ReturnValue()) | ||||
{ | { | ||||
// lock 2 locks, without deadlock, special case for better codegen and reduced metaprogramming for common case | // lock 2 locks, without deadlock, special case for better codegen and reduced metaprogramming for common case | ||||
#if defined(__GNUC__) | |||||
for (;;) | |||||
{ | |||||
auto _Result__ = LOCK_ASSEMBLE_AWAIT(_Lock_attempt_small2(_LkN, 0, 1)); | |||||
if (!_Result__) break; | |||||
_Result__ = LOCK_ASSEMBLE_AWAIT(_Lock_attempt_small2(_LkN, 1, 0)); | |||||
if (!_Result__) break; | |||||
} | |||||
#else | |||||
while (LOCK_ASSEMBLE_AWAIT(_Lock_attempt_small2(_LkN, 0, 1)) && | while (LOCK_ASSEMBLE_AWAIT(_Lock_attempt_small2(_LkN, 0, 1)) && | ||||
LOCK_ASSEMBLE_AWAIT(_Lock_attempt_small2(_LkN, 1, 0))) | LOCK_ASSEMBLE_AWAIT(_Lock_attempt_small2(_LkN, 1, 0))) | ||||
{ // keep trying | { // keep trying | ||||
} | } | ||||
#endif | |||||
} | } | ||||
template<_LockAssembleT _LA> | template<_LockAssembleT _LA> |
{ | { | ||||
using namespace std::chrono; | using namespace std::chrono; | ||||
if (co_await e.wait() == false) | |||||
auto result = co_await e.wait(); | |||||
if (result == false) | |||||
std::cout << "time out!" << std::endl; | std::cout << "time out!" << std::endl; | ||||
else | else | ||||
std::cout << "event signal!" << std::endl; | std::cout << "event signal!" << std::endl; | ||||
go[&]() -> future_t<> | go[&]() -> future_t<> | ||||
{ | { | ||||
if (co_await event_t::wait_all(std::initializer_list<event_t>{ evt1, evt2, evt3 })) | |||||
auto result = co_await event_t::wait_all(std::initializer_list<event_t>{ evt1, evt2, evt3 }); | |||||
if (result) | |||||
std::cout << "all event signal!" << std::endl; | std::cout << "all event signal!" << std::endl; | ||||
else | else | ||||
std::cout << "time out!" << std::endl; | std::cout << "time out!" << std::endl; | ||||
go[&]() -> future_t<> | go[&]() -> future_t<> | ||||
{ | { | ||||
if (co_await event_t::wait_all(evts)) | |||||
auto result = co_await event_t::wait_all(evts); | |||||
if (result) | |||||
std::cout << "all event signal!" << std::endl; | std::cout << "all event signal!" << std::endl; | ||||
else | else | ||||
std::cout << "time out!" << std::endl; | std::cout << "time out!" << std::endl; | ||||
go[&]() -> future_t<> | go[&]() -> future_t<> | ||||
{ | { | ||||
if (co_await event_t::wait_all_for(1000ms, evts)) | |||||
auto result = co_await event_t::wait_all_for(1000ms, evts); | |||||
if (result) | |||||
std::cout << "all event signal!" << std::endl; | std::cout << "all event signal!" << std::endl; | ||||
else | else | ||||
std::cout << "time out!" << std::endl; | std::cout << "time out!" << std::endl; |
intptr_t counter = 0; | intptr_t counter = 0; | ||||
for (;;) | for (;;) | ||||
{ | { | ||||
if (co_await evt.wait_for(100ms)) | |||||
auto result = co_await evt.wait_for(100ms); | |||||
if (result) | |||||
break; | break; | ||||
++counter; | ++counter; | ||||
std::cout << "."; | std::cout << "."; | ||||
intptr_t counter = 0; | intptr_t counter = 0; | ||||
for (;;) | for (;;) | ||||
{ | { | ||||
if (co_await event_t::wait_all_for(1500ms, evts)) | |||||
auto result = co_await event_t::wait_all_for(1500ms, evts); | |||||
if (result) | |||||
{ | { | ||||
std::cout << counter << std::endl; | std::cout << counter << std::endl; | ||||
std::cout << "all event signal!" << std::endl; | std::cout << "all event signal!" << std::endl; |
static future_t<> resumable_wait_event(event_v2::event_t e, int idx) | static future_t<> resumable_wait_event(event_v2::event_t e, int idx) | ||||
{ | { | ||||
if (co_await e) | |||||
auto result = co_await e; | |||||
if (result) | |||||
std::cout << "[" << idx << "]event signal!" << std::endl; | std::cout << "[" << idx << "]event signal!" << std::endl; | ||||
else | else | ||||
std::cout << "[" << idx << "]time out!" << std::endl; | std::cout << "[" << idx << "]time out!" << std::endl; | ||||
static future_t<> resumable_wait_timeout(event_v2::event_t e, milliseconds dt, int idx) | static future_t<> resumable_wait_timeout(event_v2::event_t e, milliseconds dt, int idx) | ||||
{ | { | ||||
if (co_await e.wait_for(dt)) | |||||
auto result = co_await e.wait_for(dt); | |||||
if (result) | |||||
std::cout << "[" << idx << "]event signal!" << std::endl; | std::cout << "[" << idx << "]event signal!" << std::endl; | ||||
else | else | ||||
std::cout << "[" << idx << "]time out!" << std::endl; | std::cout << "[" << idx << "]time out!" << std::endl; |
using promise_type = typename future_type::promise_type; | using promise_type = typename future_type::promise_type; | ||||
using state_type = typename future_type::state_type; | using state_type = typename future_type::state_type; | ||||
void* frame_ptr = _coro_frame_ptr(); | |||||
void* frame_ptr = __builtin_coro_frame(); | |||||
auto handler = coroutine_handle<promise_type>::from_address(frame_ptr); | auto handler = coroutine_handle<promise_type>::from_address(frame_ptr); | ||||
promise_type* promise = &handler.promise(); | promise_type* promise = &handler.promise(); | ||||
state_type* state = handler.promise().get_state(); | state_type* state = handler.promise().get_state(); | ||||
std::cout << " future size=" << sizeof(future_type) << " / " << _Align_size<future_type>() << std::endl; | std::cout << " future size=" << sizeof(future_type) << " / " << _Align_size<future_type>() << std::endl; | ||||
std::cout << " promise size=" << sizeof(promise_type) << " / " << _Align_size<promise_type>() << std::endl; | std::cout << " promise size=" << sizeof(promise_type) << " / " << _Align_size<promise_type>() << std::endl; | ||||
std::cout << " state size=" << sizeof(state_type) << " / "<< _Align_size<state_type>() << std::endl; | std::cout << " state size=" << sizeof(state_type) << " / "<< _Align_size<state_type>() << std::endl; | ||||
std::cout << " frame size=" << _coro_frame_size() << ", alloc size=" << state->get_alloc_size() << std::endl; | |||||
std::cout << " frame size=" << __builtin_coro_size() << ", alloc size=" << state->get_alloc_size() << std::endl; | |||||
std::cout << " frame ptr=" << frame_ptr << "," << (void*)&frame_ptr << std::endl; | std::cout << " frame ptr=" << frame_ptr << "," << (void*)&frame_ptr << std::endl; | ||||
std::cout << " frame end=" << (void*)((char*)(frame_ptr)+_coro_frame_size()) << std::endl; | |||||
std::cout << " frame end=" << (void*)((char*)(frame_ptr)+__builtin_coro_size()) << std::endl; | |||||
std::cout << " promise ptr=" << promise << "," << (void*)&promise << std::endl; | std::cout << " promise ptr=" << promise << "," << (void*)&promise << std::endl; | ||||
std::cout << " handle ptr=" << handler.address() << "," << (void*)&handler << std::endl; | std::cout << " handle ptr=" << handler.address() << "," << (void*)&handler << std::endl; | ||||
std::cout << " state ptr=" << state << "," << (void*)&state << std::endl; | std::cout << " state ptr=" << state << "," << (void*)&state << std::endl; | ||||
using promise_type = typename future_type::promise_type; | using promise_type = typename future_type::promise_type; | ||||
using state_type = typename future_type::state_type; | using state_type = typename future_type::state_type; | ||||
void* frame_ptr = _coro_frame_ptr(); | |||||
void* frame_ptr = __builtin_coro_frame(); | |||||
auto handler = coroutine_handle<promise_type>::from_address(frame_ptr); | auto handler = coroutine_handle<promise_type>::from_address(frame_ptr); | ||||
promise_type * promise = &handler.promise(); | promise_type * promise = &handler.promise(); | ||||
state_type * state = handler.promise().get_state(); | state_type * state = handler.promise().get_state(); | ||||
std::cout << " future size=" << sizeof(future_type) << " / " << _Align_size<future_type>() << std::endl; | std::cout << " future size=" << sizeof(future_type) << " / " << _Align_size<future_type>() << std::endl; | ||||
std::cout << " promise size=" << sizeof(promise_type) << " / " << _Align_size<promise_type>() << std::endl; | std::cout << " promise size=" << sizeof(promise_type) << " / " << _Align_size<promise_type>() << std::endl; | ||||
std::cout << " state size=" << sizeof(state_type) << " / "<< _Align_size<state_type>() << std::endl; | std::cout << " state size=" << sizeof(state_type) << " / "<< _Align_size<state_type>() << std::endl; | ||||
std::cout << " frame size=" << _coro_frame_size() << ", alloc size=" << state->get_alloc_size() << std::endl; | |||||
std::cout << " frame size=" << __builtin_coro_size() << ", alloc size=" << state->get_alloc_size() << std::endl; | |||||
std::cout << " frame ptr=" << frame_ptr << ","<< (void*)&frame_ptr << std::endl; | std::cout << " frame ptr=" << frame_ptr << ","<< (void*)&frame_ptr << std::endl; | ||||
std::cout << " frame end=" << (void *)((char*)(frame_ptr) + _coro_frame_size()) << std::endl; | |||||
std::cout << " frame end=" << (void *)((char*)(frame_ptr) + __builtin_coro_size()) << std::endl; | |||||
std::cout << " promise ptr=" << promise << "," << (void *)&promise << std::endl; | std::cout << " promise ptr=" << promise << "," << (void *)&promise << std::endl; | ||||
std::cout << " handle ptr=" << handler.address() << "," << (void*)&handler << std::endl; | std::cout << " handle ptr=" << handler.address() << "," << (void*)&handler << std::endl; | ||||
std::cout << " state ptr=" << state << "," << (void*)&state << std::endl; | std::cout << " state ptr=" << state << "," << (void*)&state << std::endl; |
for (size_t i = 0; i < N; ++i) | for (size_t i = 0; i < N; ++i) | ||||
{ | { | ||||
{ | { | ||||
while (!co_await g_lock.try_lock()) | |||||
for (;;) | |||||
{ | |||||
auto result = co_await g_lock.try_lock(); | |||||
if (result) break; | |||||
co_await yield(); | co_await yield(); | ||||
} | |||||
++g_counter; | ++g_counter; | ||||
std::cout << "push:" << g_counter << " on " << idx << std::endl; | std::cout << "push:" << g_counter << " on " << idx << std::endl; | ||||
for (size_t i = 0; i < N; ++i) | for (size_t i = 0; i < N; ++i) | ||||
{ | { | ||||
{ | { | ||||
while (!co_await g_lock.try_lock_for(10ms)) | |||||
for (;;) | |||||
{ | |||||
auto result = co_await g_lock.try_lock_for(10ms); | |||||
if (result) break; | |||||
co_await yield(); | co_await yield(); | ||||
} | |||||
++g_counter; | ++g_counter; | ||||
std::cout << "push:" << g_counter << " on " << idx << std::endl; | std::cout << "push:" << g_counter << " on " << idx << std::endl; |
{ | { | ||||
co_await resumef::sleep_for(100ms); | co_await resumef::sleep_for(100ms); | ||||
std::cout << "timer after 100ms" << std::endl; | std::cout << "timer after 100ms" << std::endl; | ||||
std::cout << "1:frame=" << _coro_frame_ptr() << std::endl; | |||||
std::cout << "1:frame=" << __builtin_coro_frame() << std::endl; | |||||
} | } | ||||
} | } | ||||
std::cout << "test_routine_use_timer_2" << std::endl; | std::cout << "test_routine_use_timer_2" << std::endl; | ||||
co_await test_routine_use_timer(); | co_await test_routine_use_timer(); | ||||
std::cout << "2:frame=" << _coro_frame_ptr() << std::endl; | |||||
std::cout << "2:frame=" << __builtin_coro_frame() << std::endl; | |||||
co_await test_routine_use_timer(); | co_await test_routine_use_timer(); | ||||
std::cout << "2:frame=" << _coro_frame_ptr() << std::endl; | |||||
std::cout << "2:frame=" << __builtin_coro_frame() << std::endl; | |||||
co_await test_routine_use_timer(); | co_await test_routine_use_timer(); | ||||
std::cout << "2:frame=" << _coro_frame_ptr() << std::endl; | |||||
std::cout << "2:frame=" << __builtin_coro_frame() << std::endl; | |||||
} | } | ||||
void resumable_main_routine() | void resumable_main_routine() |
go[&]() -> future_t<> | go[&]() -> future_t<> | ||||
{ | { | ||||
if (co_await event_t::wait_all(evts)) | |||||
auto result = co_await event_t::wait_all(evts); | |||||
if (result) | |||||
std::cout << "all event signal!" << std::endl; | std::cout << "all event signal!" << std::endl; | ||||
else | else | ||||
std::cout << "time out!" << std::endl; | std::cout << "time out!" << std::endl; |
(void)c_done.write(true); | (void)c_done.write(true); | ||||
} | } | ||||
static future_t<> resumable_main_switch_scheduler_fix_gcc_bugs(std::thread & other, channel_t<bool> c_done) | |||||
{ | |||||
co_await c_done; //第一次等待,等待run_in_thread准备好了 | |||||
std::cout << "other thread = " << other.get_id(); | |||||
std::cout << ", sch_in_thread = " << sch_in_thread << std::endl; | |||||
go resumable_get_long_switch_scheduler(1, c_done); //开启另外一个协程 | |||||
//co_await resumable_get_long(3, c_done); | |||||
co_await c_done; //等待新的协程运行完毕,从而保证主线程的协程不会提早退出 | |||||
} | |||||
void resumable_main_switch_scheduler() | void resumable_main_switch_scheduler() | ||||
{ | { | ||||
sch_in_main = this_scheduler(); | sch_in_main = this_scheduler(); | ||||
channel_t<bool> c_done{ 1 }; | channel_t<bool> c_done{ 1 }; | ||||
std::thread other(&run_in_thread, std::ref(c_done)); | std::thread other(&run_in_thread, std::ref(c_done)); | ||||
#if defined(__GNUC__) | |||||
go resumable_main_switch_scheduler_fix_gcc_bugs(other, c_done); | |||||
#else | |||||
go[&other, c_done]()->future_t<> | go[&other, c_done]()->future_t<> | ||||
{ | { | ||||
co_await c_done; //第一次等待,等待run_in_thread准备好了 | co_await c_done; //第一次等待,等待run_in_thread准备好了 | ||||
go resumable_get_long_switch_scheduler(1, c_done); //开启另外一个协程 | go resumable_get_long_switch_scheduler(1, c_done); //开启另外一个协程 | ||||
//co_await resumable_get_long(3, c_done); | //co_await resumable_get_long(3, c_done); | ||||
co_await c_done; //等待新的协程运行完毕,从而保证主线程的协程不会提早退出 | co_await c_done; //等待新的协程运行完毕,从而保证主线程的协程不会提早退出 | ||||
}; | |||||
}; //GCC: internal compiler error: in captures_temporary, at cp/coroutines.cc:2716 | |||||
#endif | |||||
sch_in_main->run_until_notask(); | sch_in_main->run_until_notask(); | ||||