@@ -38,6 +38,9 @@ RESUMEF_NS | |||
template<typename _PromiseT = void> | |||
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; | |||
@@ -121,17 +121,17 @@ RESUMEF_NS | |||
return generator_t{ *this }; | |||
} | |||
std::experimental::suspend_always initial_suspend() noexcept | |||
suspend_always initial_suspend() noexcept | |||
{ | |||
return {}; | |||
} | |||
std::experimental::suspend_always final_suspend() noexcept | |||
suspend_always final_suspend() noexcept | |||
{ | |||
return {}; | |||
} | |||
std::experimental::suspend_always yield_value(_Ty const& _Value) noexcept | |||
suspend_always yield_value(_Ty const& _Value) noexcept | |||
{ | |||
_CurrentValue = std::addressof(_Value); | |||
return {}; |
@@ -128,6 +128,24 @@ RESUMEF_NS | |||
> | |||
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 在非协程中,无死锁的批量加锁。会阻塞当前线程,直到获得所有锁为止。 |
@@ -76,20 +76,20 @@ RESUMEF_NS | |||
private: | |||
void* _Address; | |||
public: | |||
std::vector<mutex_t> _Lks; | |||
std::vector<mutex_t> _mutex; | |||
template<class... _Mtxs> | |||
_MutexAddressAssembleT(void* unique_address, _Mtxs&... mtxs) | |||
: _Address(unique_address) | |||
, _Lks({ mtxs... }) | |||
, _mutex({ mtxs... }) | |||
{} | |||
size_t size() const | |||
{ | |||
return _Lks.size(); | |||
return _mutex.size(); | |||
} | |||
mutex_t& operator[](int _Idx) | |||
{ | |||
return _Lks[_Idx]; | |||
return _mutex[_Idx]; | |||
} | |||
void _Lock_ref(mutex_t& _LkN) const | |||
{ | |||
@@ -540,18 +540,40 @@ RESUMEF_NS | |||
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> | |||
inline scoped_unlock_t<_Mtxs...> mutex_t::lock(void* unique_address, _Mtxs&... mtxs) | |||
{ | |||
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> | |||
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::_MutexAddressAssembleT _MAA{ unique_address, mtxs... }; | |||
detail::scoped_lock_range_lock_impl::_Lock_range(_MAA); | |||
} | |||
@@ -560,7 +582,7 @@ RESUMEF_NS | |||
{ | |||
assert(unique_address != nullptr); | |||
(..., mtxs.unlock(unique_address)); | |||
(mtxs.unlock(unique_address), ...); | |||
} | |||
} | |||
} |
@@ -53,7 +53,7 @@ RESUMEF_NS | |||
template<class U> | |||
void return_value(U&& val); //co_return val | |||
template<class U> | |||
std::experimental::suspend_always yield_value(U&& val); | |||
suspend_always yield_value(U&& val); | |||
}; | |||
template<class _Ty> | |||
@@ -63,7 +63,7 @@ RESUMEF_NS | |||
using promise_impl_t<_Ty&>::get_return_object; | |||
void return_value(_Ty& val); //co_return val | |||
std::experimental::suspend_always yield_value(_Ty& val); | |||
suspend_always yield_value(_Ty& val); | |||
}; | |||
template<> | |||
@@ -72,7 +72,7 @@ RESUMEF_NS | |||
using promise_impl_t<void>::get_return_object; | |||
void return_void(); //co_return; | |||
std::experimental::suspend_always yield_value(); | |||
suspend_always yield_value(); | |||
}; | |||
} |
@@ -177,7 +177,7 @@ RESUMEF_NS | |||
template<class _Ty> | |||
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)); | |||
return {}; | |||
@@ -190,7 +190,7 @@ RESUMEF_NS | |||
} | |||
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); | |||
return {}; | |||
@@ -201,7 +201,7 @@ RESUMEF_NS | |||
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); | |||
return {}; |
@@ -143,7 +143,7 @@ static void resumable_mutex_async() | |||
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); | |||
assert(a.is_locked()); | |||
@@ -159,9 +159,9 @@ static future_t<> resumable_mutex_range_push(size_t idx, mutex_t a, mutex_t b, m | |||
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(b.is_locked()); | |||
assert(c.is_locked()); | |||
@@ -170,6 +170,7 @@ static future_t<> resumable_mutex_range_pop(size_t idx, mutex_t a, mutex_t b, mu | |||
//std::cout << "pop :" << g_counter << " on " << idx << std::endl; | |||
//co_await 5ms; | |||
co_await mutex_t::unlock(a, b, c); | |||
} | |||
} | |||
@@ -45,8 +45,8 @@ int main(int argc, const char* argv[]) | |||
//test_ring_queue<resumef::ring_queue_spinlock<int, false, uint32_t>>(); | |||
//test_ring_queue<resumef::ring_queue_lockfree<int, uint64_t>>(); | |||
//resumable_main_mutex(); | |||
//return 0; | |||
resumable_main_mutex(); | |||
return 0; | |||
//if (argc > 1) | |||
// resumable_main_benchmark_asio_client(atoi(argv[1])); |