template<typename _PromiseT = void> | template<typename _PromiseT = void> | ||||
using coroutine_handle = std::experimental::coroutine_handle<_PromiseT>; | using coroutine_handle = std::experimental::coroutine_handle<_PromiseT>; | ||||
using suspend_if = std::experimental::suspend_if; | |||||
using suspend_always = std::experimental::suspend_always; | |||||
using suspend_never = std::experimental::suspend_never; | |||||
struct state_base_t; | struct state_base_t; | ||||
return generator_t{ *this }; | return generator_t{ *this }; | ||||
} | } | ||||
std::experimental::suspend_always initial_suspend() noexcept | |||||
suspend_always initial_suspend() noexcept | |||||
{ | { | ||||
return {}; | return {}; | ||||
} | } | ||||
std::experimental::suspend_always final_suspend() noexcept | |||||
suspend_always final_suspend() noexcept | |||||
{ | { | ||||
return {}; | return {}; | ||||
} | } | ||||
std::experimental::suspend_always yield_value(_Ty const& _Value) noexcept | |||||
suspend_always yield_value(_Ty const& _Value) noexcept | |||||
{ | { | ||||
_CurrentValue = std::addressof(_Value); | _CurrentValue = std::addressof(_Value); | ||||
return {}; | return {}; |
> | > | ||||
static future_t<scoped_unlock_t<_Mtxs...>> lock(_Mtxs&... mtxs); | static future_t<scoped_unlock_t<_Mtxs...>> lock(_Mtxs&... mtxs); | ||||
/** | |||||
* @brief 在协程中,无死锁的批量加锁。不会阻塞当前线程。直到获得所有锁之前,会阻塞当前协程。 | |||||
* @return [co_await] void | |||||
*/ | |||||
template<class... _Mtxs | |||||
, typename = std::enable_if_t<std::conjunction_v<std::is_same<remove_cvref_t<_Mtxs>, mutex_t>...>> | |||||
> | |||||
static future_t<> lock(adopt_manual_unlock_t, _Mtxs&... mtxs); | |||||
/** | |||||
* @brief 在协程中解锁。如果可能,使用unlock(root_state(), mtxs...)来替代。 | |||||
* @return [co_await] void | |||||
*/ | |||||
template<class... _Mtxs | |||||
, typename = std::enable_if_t<std::conjunction_v<std::is_same<remove_cvref_t<_Mtxs>, mutex_t>...>> | |||||
> | |||||
static future_t<> unlock(_Mtxs&... mtxs); | |||||
/** | /** | ||||
* @brief 在非协程中,无死锁的批量加锁。会阻塞当前线程,直到获得所有锁为止。 | * @brief 在非协程中,无死锁的批量加锁。会阻塞当前线程,直到获得所有锁为止。 |
private: | private: | ||||
void* _Address; | void* _Address; | ||||
public: | public: | ||||
std::vector<mutex_t> _Lks; | |||||
std::vector<mutex_t> _mutex; | |||||
template<class... _Mtxs> | template<class... _Mtxs> | ||||
_MutexAddressAssembleT(void* unique_address, _Mtxs&... mtxs) | _MutexAddressAssembleT(void* unique_address, _Mtxs&... mtxs) | ||||
: _Address(unique_address) | : _Address(unique_address) | ||||
, _Lks({ mtxs... }) | |||||
, _mutex({ mtxs... }) | |||||
{} | {} | ||||
size_t size() const | size_t size() const | ||||
{ | { | ||||
return _Lks.size(); | |||||
return _mutex.size(); | |||||
} | } | ||||
mutex_t& operator[](int _Idx) | mutex_t& operator[](int _Idx) | ||||
{ | { | ||||
return _Lks[_Idx]; | |||||
return _mutex[_Idx]; | |||||
} | } | ||||
void _Lock_ref(mutex_t& _LkN) const | void _Lock_ref(mutex_t& _LkN) const | ||||
{ | { | ||||
co_return std::move(unlock_guard); | co_return std::move(unlock_guard); | ||||
} | } | ||||
template<class... _Mtxs, typename> | |||||
inline future_t<> mutex_t::lock(adopt_manual_unlock_t, _Mtxs&... mtxs) | |||||
{ | |||||
mutex_t::_MutexAwaitAssembleT _MAA{ root_state(), mtxs... }; | |||||
co_await detail::mutex_lock_await_lock_impl::_Lock_range(_MAA); | |||||
} | |||||
template<class... _Mtxs, typename> | |||||
inline future_t<> mutex_t::unlock(_Mtxs&... mtxs) | |||||
{ | |||||
void* unique_address = root_state(); | |||||
(mtxs.unlock(unique_address), ...); | |||||
} | |||||
template<class... _Mtxs, typename> | template<class... _Mtxs, typename> | ||||
inline scoped_unlock_t<_Mtxs...> mutex_t::lock(void* unique_address, _Mtxs&... mtxs) | inline scoped_unlock_t<_Mtxs...> mutex_t::lock(void* unique_address, _Mtxs&... mtxs) | ||||
{ | { | ||||
assert(unique_address != nullptr); | assert(unique_address != nullptr); | ||||
return { unique_address, mtxs... }; | |||||
detail::_MutexAddressAssembleT _MAA{ unique_address, mtxs... }; | |||||
detail::scoped_lock_range_lock_impl::_Lock_range(_MAA); | |||||
scoped_unlock_t<_Mtxs...> su{ std::adopt_lock, unique_address }; | |||||
su._MAA._mutex = std::move(_MAA._mutex); | |||||
return su; | |||||
} | } | ||||
template<class... _Mtxs, typename> | template<class... _Mtxs, typename> | ||||
inline void mutex_t::lock(adopt_manual_unlock_t, void* unique_address, _Mtxs&... mtxs) | inline void mutex_t::lock(adopt_manual_unlock_t, void* unique_address, _Mtxs&... mtxs) | ||||
{ | { | ||||
assert(unique_address != nullptr); | assert(unique_address != nullptr); | ||||
mutex_t::_MutexAwaitAssembleT _MAA{ unique_address, mtxs... }; | |||||
detail::_MutexAddressAssembleT _MAA{ unique_address, mtxs... }; | |||||
detail::scoped_lock_range_lock_impl::_Lock_range(_MAA); | detail::scoped_lock_range_lock_impl::_Lock_range(_MAA); | ||||
} | } | ||||
{ | { | ||||
assert(unique_address != nullptr); | assert(unique_address != nullptr); | ||||
(..., mtxs.unlock(unique_address)); | |||||
(mtxs.unlock(unique_address), ...); | |||||
} | } | ||||
} | } | ||||
} | } |
template<class U> | template<class U> | ||||
void return_value(U&& val); //co_return val | void return_value(U&& val); //co_return val | ||||
template<class U> | template<class U> | ||||
std::experimental::suspend_always yield_value(U&& val); | |||||
suspend_always yield_value(U&& val); | |||||
}; | }; | ||||
template<class _Ty> | template<class _Ty> | ||||
using promise_impl_t<_Ty&>::get_return_object; | using promise_impl_t<_Ty&>::get_return_object; | ||||
void return_value(_Ty& val); //co_return val | void return_value(_Ty& val); //co_return val | ||||
std::experimental::suspend_always yield_value(_Ty& val); | |||||
suspend_always yield_value(_Ty& val); | |||||
}; | }; | ||||
template<> | template<> | ||||
using promise_impl_t<void>::get_return_object; | using promise_impl_t<void>::get_return_object; | ||||
void return_void(); //co_return; | void return_void(); //co_return; | ||||
std::experimental::suspend_always yield_value(); | |||||
suspend_always yield_value(); | |||||
}; | }; | ||||
} | } |
template<class _Ty> | template<class _Ty> | ||||
template<class U> | template<class U> | ||||
inline std::experimental::suspend_always promise_t<_Ty>::yield_value(U&& val) | |||||
inline suspend_always promise_t<_Ty>::yield_value(U&& val) | |||||
{ | { | ||||
this->get_state()->promise_yield_value(this, std::forward<U>(val)); | this->get_state()->promise_yield_value(this, std::forward<U>(val)); | ||||
return {}; | return {}; | ||||
} | } | ||||
template<class _Ty> | template<class _Ty> | ||||
inline std::experimental::suspend_always promise_t<_Ty&>::yield_value(_Ty& val) | |||||
inline suspend_always promise_t<_Ty&>::yield_value(_Ty& val) | |||||
{ | { | ||||
this->get_state()->promise_yield_value(this, val); | this->get_state()->promise_yield_value(this, val); | ||||
return {}; | return {}; | ||||
this->get_state()->set_value(); | this->get_state()->set_value(); | ||||
} | } | ||||
inline std::experimental::suspend_always promise_t<void>::yield_value() | |||||
inline suspend_always promise_t<void>::yield_value() | |||||
{ | { | ||||
this->get_state()->promise_yield_value(this); | this->get_state()->promise_yield_value(this); | ||||
return {}; | return {}; |
static future_t<> resumable_mutex_range_push(size_t idx, mutex_t a, mutex_t b, mutex_t c) | static future_t<> resumable_mutex_range_push(size_t idx, mutex_t a, mutex_t b, mutex_t c) | ||||
{ | { | ||||
for (int i = 0; i < 100000; ++i) | |||||
for (int i = 0; i < 10000; ++i) | |||||
{ | { | ||||
scoped_unlock_t __lockers = co_await mutex_t::lock(a, b, c); | scoped_unlock_t __lockers = co_await mutex_t::lock(a, b, c); | ||||
assert(a.is_locked()); | assert(a.is_locked()); | ||||
static future_t<> resumable_mutex_range_pop(size_t idx, mutex_t a, mutex_t b, mutex_t c) | static future_t<> resumable_mutex_range_pop(size_t idx, mutex_t a, mutex_t b, mutex_t c) | ||||
{ | { | ||||
for (int i = 0; i < 100000; ++i) | |||||
for (int i = 0; i < 10000; ++i) | |||||
{ | { | ||||
scoped_unlock_t __lockers = co_await mutex_t::lock(a, b, c); | |||||
co_await mutex_t::lock(adopt_manual_unlock, a, b, c); | |||||
assert(a.is_locked()); | assert(a.is_locked()); | ||||
assert(b.is_locked()); | assert(b.is_locked()); | ||||
assert(c.is_locked()); | assert(c.is_locked()); | ||||
//std::cout << "pop :" << g_counter << " on " << idx << std::endl; | //std::cout << "pop :" << g_counter << " on " << idx << std::endl; | ||||
//co_await 5ms; | //co_await 5ms; | ||||
co_await mutex_t::unlock(a, b, c); | |||||
} | } | ||||
} | } | ||||
//test_ring_queue<resumef::ring_queue_spinlock<int, false, uint32_t>>(); | //test_ring_queue<resumef::ring_queue_spinlock<int, false, uint32_t>>(); | ||||
//test_ring_queue<resumef::ring_queue_lockfree<int, uint64_t>>(); | //test_ring_queue<resumef::ring_queue_lockfree<int, uint64_t>>(); | ||||
//resumable_main_mutex(); | |||||
//return 0; | |||||
resumable_main_mutex(); | |||||
return 0; | |||||
//if (argc > 1) | //if (argc > 1) | ||||
// resumable_main_benchmark_asio_client(atoi(argv[1])); | // resumable_main_benchmark_asio_client(atoi(argv[1])); |