struct [[nodiscard]] scoped_unlock_t; | struct [[nodiscard]] scoped_unlock_t; | ||||
//支持递归的锁 | //支持递归的锁 | ||||
//锁被本协程所在的跟协程所拥有。支持在跟协程下的所有协程里递归加锁。 | |||||
struct mutex_t | struct mutex_t | ||||
{ | { | ||||
bool is_locked() const; | bool is_locked() const; | ||||
struct [[nodiscard]] awaiter; | struct [[nodiscard]] awaiter; | ||||
struct [[nodiscard]] manual_awaiter; | struct [[nodiscard]] manual_awaiter; | ||||
/** | |||||
* @brief 在协程中加锁。 | |||||
* @return [co_await] scoped_unlock_t | |||||
*/ | |||||
awaiter/*scoped_unlock_t*/ lock() const noexcept; | awaiter/*scoped_unlock_t*/ lock() const noexcept; | ||||
/** | |||||
* @brief 等同调用co_await lock()。 | |||||
* @return [co_await] scoped_unlock_t | |||||
*/ | |||||
awaiter/*scoped_unlock_t*/ operator co_await() const noexcept; | awaiter/*scoped_unlock_t*/ operator co_await() const noexcept; | ||||
/** | |||||
* @brief 在协程中加锁。需要随后调用unlock()函数解锁。lock()/unlock()调用必须在同一个跟协程下配对调用。 | |||||
* @return [co_await] void | |||||
*/ | |||||
manual_awaiter/*void*/ lock(adopt_manual_unlock_t) const noexcept; | manual_awaiter/*void*/ lock(adopt_manual_unlock_t) const noexcept; | ||||
struct [[nodiscard]] try_awaiter; | struct [[nodiscard]] try_awaiter; | ||||
//co_await try_lock()获得是否加锁成功。此操作无论成功与否都会立即返回。 | |||||
//如果加锁成功,则需要调用co_await unlock()解锁。或者使用unlock(root_state())解锁。 | |||||
//如果加锁失败,且要循环尝试加锁,则最好调用co_await yield()让出一次调度。否则,可能造成本调度器死循环。 | |||||
/** | |||||
* @brief 尝试在协程中加锁。此操作无论成功与否都会立即返回。 | |||||
* 如果加锁成功,则需要调用co_await unlock()解锁。或者使用unlock(root_state())解锁。 | |||||
* 如果加锁失败,且要循环尝试加锁,则最好调用co_await yield()让出一次调度。否则,可能造成本调度器死循环。 | |||||
* @return [co_await] bool | |||||
*/ | |||||
try_awaiter/*bool*/ try_lock() const noexcept; | try_awaiter/*bool*/ try_lock() const noexcept; | ||||
//此操作立即返回 | |||||
/** | |||||
* @brief 在协程中解锁。此操作立即返回。 | |||||
* @return [co_await] void | |||||
*/ | |||||
struct [[nodiscard]] unlock_awaiter; | struct [[nodiscard]] unlock_awaiter; | ||||
unlock_awaiter/*void*/ unlock() const noexcept; | unlock_awaiter/*void*/ unlock() const noexcept; | ||||
struct [[nodiscard]] timeout_awaiter; | struct [[nodiscard]] timeout_awaiter; | ||||
/** | |||||
* @brief 在协程中尝试加锁,直到超时 | |||||
* @param dt 超时时长 | |||||
* @return [co_await] bool | |||||
*/ | |||||
template <class _Rep, class _Period> | template <class _Rep, class _Period> | ||||
timeout_awaiter/*bool*/ try_lock_for(const std::chrono::duration<_Rep, _Period>& dt) const noexcept; | timeout_awaiter/*bool*/ try_lock_for(const std::chrono::duration<_Rep, _Period>& dt) const noexcept; | ||||
/** | |||||
* @brief 在协程中尝试加锁,直到超时 | |||||
* @param tp 超时时刻 | |||||
* @return [co_await] bool | |||||
*/ | |||||
template <class _Rep, class _Period> | template <class _Rep, class _Period> | ||||
timeout_awaiter/*bool*/ try_lock_until(const std::chrono::time_point<_Rep, _Period>& tp) const noexcept; | timeout_awaiter/*bool*/ try_lock_until(const std::chrono::time_point<_Rep, _Period>& tp) const noexcept; | ||||
void unlock(void* unique_address) const; | void unlock(void* unique_address) const; | ||||
/** | |||||
* @brief 在协程中,无死锁的批量加锁。捕获阻塞当前线程。直到获得所有锁之前,阻塞当前协程。 | |||||
* @return [co_await] scoped_unlock_t | |||||
*/ | |||||
template<class... _Mtxs | template<class... _Mtxs | ||||
, typename = std::enable_if_t<std::conjunction_v<std::is_same<remove_cvref_t<_Mtxs>, mutex_t>...>> | , typename = std::enable_if_t<std::conjunction_v<std::is_same<remove_cvref_t<_Mtxs>, mutex_t>...>> | ||||
> | > | ||||
static future_t<scoped_unlock_t<_Mtxs...>> lock(_Mtxs&... mtxs); | static future_t<scoped_unlock_t<_Mtxs...>> lock(_Mtxs&... mtxs); | ||||
/** | |||||
* @brief 在非协程中,无死锁的批量加锁。会阻塞当前线程,直到获得所有锁为止。 | |||||
* @return scoped_unlock_t | |||||
*/ | |||||
template<class... _Mtxs | template<class... _Mtxs | ||||
, typename = std::enable_if_t<std::conjunction_v<std::is_same<remove_cvref_t<_Mtxs>, mutex_t>...>> | , typename = std::enable_if_t<std::conjunction_v<std::is_same<remove_cvref_t<_Mtxs>, mutex_t>...>> | ||||
> | > | ||||
static scoped_unlock_t<_Mtxs...> lock(void* unique_address, _Mtxs&... mtxs); | static scoped_unlock_t<_Mtxs...> lock(void* unique_address, _Mtxs&... mtxs); | ||||
/** | |||||
* @brief 在非协程中,无死锁的批量加锁。会阻塞当前线程,直到获得所有锁为止。 | |||||
*/ | |||||
template<class... _Mtxs | |||||
, typename = std::enable_if_t<std::conjunction_v<std::is_same<remove_cvref_t<_Mtxs>, mutex_t>...>> | |||||
> | |||||
static void lock(adopt_manual_unlock_t, void* unique_address, _Mtxs&... mtxs); | |||||
/** | |||||
* @brief 在非协程中,批量解锁加锁。立即返回。 | |||||
*/ | |||||
template<class... _Mtxs | template<class... _Mtxs | ||||
, typename = std::enable_if_t<std::conjunction_v<std::is_same<remove_cvref_t<_Mtxs>, mutex_t>...>> | , typename = std::enable_if_t<std::conjunction_v<std::is_same<remove_cvref_t<_Mtxs>, mutex_t>...>> | ||||
> | > |
return { unique_address, mtxs... }; | return { unique_address, mtxs... }; | ||||
} | } | ||||
template<class... _Mtxs, typename> | |||||
inline void mutex_t::lock(adopt_manual_unlock_t, void* unique_address, _Mtxs&... mtxs) | |||||
{ | |||||
assert(unique_address != nullptr); | |||||
mutex_t::_MutexAwaitAssembleT _MAA{ unique_address, mtxs... }; | |||||
detail::scoped_lock_range_lock_impl::_Lock_range(_MAA); | |||||
} | |||||
template<class... _Mtxs, typename> | template<class... _Mtxs, typename> | ||||
inline void mutex_t::unlock(void* unique_address, _Mtxs&... mtxs) | inline void mutex_t::unlock(void* unique_address, _Mtxs&... mtxs) | ||||
{ | { |
static _Sty* _Construct(void* _Ptr, size_t _Size) | static _Sty* _Construct(void* _Ptr, size_t _Size) | ||||
{ | { | ||||
_Sty* st = new(_Ptr) _Sty(false); | _Sty* st = new(_Ptr) _Sty(false); | ||||
st->_alloc_size = _Size; | |||||
st->_alloc_size = static_cast<uint32_t>(_Size); | |||||
return st; | return st; | ||||
} | } | ||||
#endif | #endif | ||||
char* _Ptr = _Al.allocate(_Size); | char* _Ptr = _Al.allocate(_Size); | ||||
_Sty* st = new(_Ptr) _Sty(awaitor); | _Sty* st = new(_Ptr) _Sty(awaitor); | ||||
st->_alloc_size = _Size; | |||||
st->_alloc_size = static_cast<uint32_t>(_Size); | |||||
return st; | return st; | ||||
} | } |
| | ||||
#include "librf.h" | #include "librf.h" | ||||
#include <optional> | #include <optional> | ||||
#include <crtdbg.h> | |||||
//#define _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE 1 | //#define _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE 1 | ||||
#include "src/ring_queue.h" | #include "src/ring_queue.h" | ||||
int main(int argc, const char* argv[]) | int main(int argc, const char* argv[]) | ||||
{ | { | ||||
//_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF); | |||||
(void)argc; | (void)argc; | ||||
(void)argv; | (void)argv; | ||||
//else | //else | ||||
// resumable_main_benchmark_asio_server(); | // resumable_main_benchmark_asio_server(); | ||||
resumable_main_cb(); | |||||
resumable_main_layout(); | |||||
resumable_main_modern_cb(); | |||||
resumable_main_suspend_always(); | |||||
resumable_main_yield_return(); | |||||
resumable_main_resumable(); | |||||
resumable_main_routine(); | |||||
resumable_main_exception(); | |||||
resumable_main_dynamic_go(); | |||||
resumable_main_multi_thread(); | |||||
resumable_main_timer(); | |||||
resumable_main_benchmark_mem(false); | |||||
resumable_main_mutex(); | |||||
resumable_main_event(); | |||||
resumable_main_event_v2(); | |||||
resumable_main_event_timeout(); | |||||
resumable_main_channel(); | |||||
resumable_main_channel_mult_thread(); | |||||
resumable_main_sleep(); | |||||
resumable_main_when_all(); | |||||
resumable_main_switch_scheduler(); | |||||
resumable_main_cb(); _CrtCheckMemory(); | |||||
resumable_main_layout(); _CrtCheckMemory(); | |||||
resumable_main_modern_cb(); _CrtCheckMemory(); | |||||
resumable_main_suspend_always(); _CrtCheckMemory(); | |||||
resumable_main_yield_return(); _CrtCheckMemory(); | |||||
resumable_main_resumable(); _CrtCheckMemory(); | |||||
resumable_main_routine(); _CrtCheckMemory(); | |||||
resumable_main_exception(); _CrtCheckMemory(); | |||||
resumable_main_dynamic_go(); _CrtCheckMemory(); | |||||
resumable_main_multi_thread(); _CrtCheckMemory(); | |||||
resumable_main_timer(); _CrtCheckMemory(); | |||||
resumable_main_benchmark_mem(false); _CrtCheckMemory(); | |||||
resumable_main_mutex(); _CrtCheckMemory(); | |||||
resumable_main_event(); _CrtCheckMemory(); | |||||
resumable_main_event_v2(); _CrtCheckMemory(); | |||||
resumable_main_event_timeout(); _CrtCheckMemory(); | |||||
resumable_main_channel(); _CrtCheckMemory(); | |||||
resumable_main_channel_mult_thread(); _CrtCheckMemory(); | |||||
resumable_main_sleep(); _CrtCheckMemory(); | |||||
resumable_main_when_all(); _CrtCheckMemory(); | |||||
resumable_main_switch_scheduler(); _CrtCheckMemory(); | |||||
std::cout << "ALL OK!" << std::endl; | std::cout << "ALL OK!" << std::endl; | ||||
benchmark_main_channel_passing_next(); //这是一个死循环测试 | benchmark_main_channel_passing_next(); //这是一个死循环测试 | ||||
_CrtCheckMemory(); | |||||
return 0; | return 0; | ||||
} | } |
<PlatformToolset>v142</PlatformToolset> | <PlatformToolset>v142</PlatformToolset> | ||||
<WholeProgramOptimization>true</WholeProgramOptimization> | <WholeProgramOptimization>true</WholeProgramOptimization> | ||||
<CharacterSet>NotSet</CharacterSet> | <CharacterSet>NotSet</CharacterSet> | ||||
<EnableASAN>true</EnableASAN> | |||||
</PropertyGroup> | </PropertyGroup> | ||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> | ||||
<ConfigurationType>Application</ConfigurationType> | <ConfigurationType>Application</ConfigurationType> |