EXCLUDE = channel_v1.h \ | EXCLUDE = channel_v1.h \ | ||||
event_v1.h \ | event_v1.h \ | ||||
mutex_v1.h | |||||
mutex_v1.h \ | |||||
ring_queue.h \ | |||||
ring_queue_lockfree.h \ | |||||
ring_queue_spinlock.h \ | |||||
intrusive_link_queue.h | |||||
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or | # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or | ||||
# directories that are symbolic links (a Unix file system feature) are excluded | # directories that are symbolic links (a Unix file system feature) are excluded |
struct [[nodiscard]] any_awaiter; | struct [[nodiscard]] any_awaiter; | ||||
template<class _Iter | template<class _Iter | ||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
COMMA_RESUMEF_ENABLE_IF(traits::is_iterator_of_v<_Iter, event_t>) | COMMA_RESUMEF_ENABLE_IF(traits::is_iterator_of_v<_Iter, event_t>) | ||||
> RESUMEF_REQUIRES(_IteratorOfT<_Iter, event_t>) | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
> | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
RESUMEF_REQUIRES(_IteratorOfT<_Iter, event_t>) | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
static auto wait_any(_Iter begin_, _Iter end_) | static auto wait_any(_Iter begin_, _Iter end_) | ||||
->any_awaiter<_Iter>; | ->any_awaiter<_Iter>; | ||||
template<class _Cont | template<class _Cont | ||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
COMMA_RESUMEF_ENABLE_IF(traits::is_container_of_v<_Cont, event_t>) | COMMA_RESUMEF_ENABLE_IF(traits::is_container_of_v<_Cont, event_t>) | ||||
> RESUMEF_REQUIRES(_ContainerOfT<_Cont, event_t>) | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
> | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
RESUMEF_REQUIRES(_ContainerOfT<_Cont, event_t>) | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
static auto wait_any(_Cont& cnt_) | static auto wait_any(_Cont& cnt_) | ||||
->any_awaiter<decltype(std::begin(cnt_))>; | ->any_awaiter<decltype(std::begin(cnt_))>; | ||||
struct [[nodiscard]] timeout_any_awaiter; | struct [[nodiscard]] timeout_any_awaiter; | ||||
template<class _Rep, class _Period, class _Iter | template<class _Rep, class _Period, class _Iter | ||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
COMMA_RESUMEF_ENABLE_IF(traits::is_iterator_of_v<_Iter, event_t>) | COMMA_RESUMEF_ENABLE_IF(traits::is_iterator_of_v<_Iter, event_t>) | ||||
> RESUMEF_REQUIRES(_IteratorOfT<_Iter, event_t>) | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
> | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
RESUMEF_REQUIRES(_IteratorOfT<_Iter, event_t>) | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
static auto wait_any_for(const std::chrono::duration<_Rep, _Period>& dt, _Iter begin_, _Iter end_) | static auto wait_any_for(const std::chrono::duration<_Rep, _Period>& dt, _Iter begin_, _Iter end_) | ||||
->timeout_any_awaiter<_Iter>; | ->timeout_any_awaiter<_Iter>; | ||||
template<class _Rep, class _Period, class _Cont | template<class _Rep, class _Period, class _Cont | ||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
COMMA_RESUMEF_ENABLE_IF(traits::is_container_of_v<_Cont, event_t>) | COMMA_RESUMEF_ENABLE_IF(traits::is_container_of_v<_Cont, event_t>) | ||||
> RESUMEF_REQUIRES(_ContainerOfT<_Cont, event_t>) | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
> | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
RESUMEF_REQUIRES(_ContainerOfT<_Cont, event_t>) | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
static auto wait_any_for(const std::chrono::duration<_Rep, _Period>& dt, _Cont& cnt_) | static auto wait_any_for(const std::chrono::duration<_Rep, _Period>& dt, _Cont& cnt_) | ||||
->timeout_any_awaiter<decltype(std::begin(cnt_))>; | ->timeout_any_awaiter<decltype(std::begin(cnt_))>; | ||||
struct [[nodiscard]] all_awaiter; | struct [[nodiscard]] all_awaiter; | ||||
template<class _Iter | template<class _Iter | ||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
COMMA_RESUMEF_ENABLE_IF(traits::is_iterator_of_v<_Iter, event_t>) | COMMA_RESUMEF_ENABLE_IF(traits::is_iterator_of_v<_Iter, event_t>) | ||||
> RESUMEF_REQUIRES(_IteratorOfT<_Iter, event_t>) | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
> | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
RESUMEF_REQUIRES(_IteratorOfT<_Iter, event_t>) | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
static auto wait_all(_Iter begin_, _Iter end_) | static auto wait_all(_Iter begin_, _Iter end_) | ||||
->all_awaiter<_Iter>; | ->all_awaiter<_Iter>; | ||||
template<class _Cont | template<class _Cont | ||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
COMMA_RESUMEF_ENABLE_IF(traits::is_container_of_v<_Cont, event_t>) | COMMA_RESUMEF_ENABLE_IF(traits::is_container_of_v<_Cont, event_t>) | ||||
> RESUMEF_REQUIRES(_ContainerOfT<_Cont, event_t>) | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
> | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
RESUMEF_REQUIRES(_ContainerOfT<_Cont, event_t>) | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
static auto wait_all(_Cont& cnt_) | static auto wait_all(_Cont& cnt_) | ||||
->all_awaiter<decltype(std::begin(cnt_))>; | ->all_awaiter<decltype(std::begin(cnt_))>; | ||||
struct [[nodiscard]] timeout_all_awaiter; | struct [[nodiscard]] timeout_all_awaiter; | ||||
template<class _Rep, class _Period, class _Iter | template<class _Rep, class _Period, class _Iter | ||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
COMMA_RESUMEF_ENABLE_IF(traits::is_iterator_of_v<_Iter, event_t>) | COMMA_RESUMEF_ENABLE_IF(traits::is_iterator_of_v<_Iter, event_t>) | ||||
> RESUMEF_REQUIRES(_IteratorOfT<_Iter, event_t>) | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
> | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
RESUMEF_REQUIRES(_IteratorOfT<_Iter, event_t>) | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
static auto wait_all_for(const std::chrono::duration<_Rep, _Period>& dt, _Iter begin_, _Iter end_) | static auto wait_all_for(const std::chrono::duration<_Rep, _Period>& dt, _Iter begin_, _Iter end_) | ||||
->timeout_all_awaiter<_Iter>; | ->timeout_all_awaiter<_Iter>; | ||||
template<class _Rep, class _Period, class _Cont | template<class _Rep, class _Period, class _Cont | ||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
COMMA_RESUMEF_ENABLE_IF(traits::is_container_of_v<_Cont, event_t>) | COMMA_RESUMEF_ENABLE_IF(traits::is_container_of_v<_Cont, event_t>) | ||||
> RESUMEF_REQUIRES(_ContainerOfT<_Cont, event_t>) | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
> | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
RESUMEF_REQUIRES(_ContainerOfT<_Cont, event_t>) | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
static auto wait_all_for(const std::chrono::duration<_Rep, _Period>& dt, _Cont& cnt_) | static auto wait_all_for(const std::chrono::duration<_Rep, _Period>& dt, _Cont& cnt_) | ||||
->timeout_all_awaiter<decltype(std::begin(cnt_))>; | ->timeout_all_awaiter<decltype(std::begin(cnt_))>; | ||||
lockes.emplace_back(std::ref(evt->_lock)); | lockes.emplace_back(std::ref(evt->_lock)); | ||||
} | } | ||||
scoped_lock_range<ref_lock_type> lock_(lockes); | |||||
batch_lock_t<ref_lock_type> lock_(lockes); | |||||
for (auto iter = _begin; iter != _end; ++iter) | for (auto iter = _begin; iter != _end; ++iter) | ||||
{ | { | ||||
(void)_state->on_await_suspend(handler); | (void)_state->on_await_suspend(handler); | ||||
cb(); | cb(); | ||||
scoped_lock_range<ref_lock_type> lock_(lockes); | |||||
batch_lock_t<ref_lock_type> lock_(lockes); | |||||
for (auto iter = _begin; iter != _end; ++iter) | for (auto iter = _begin; iter != _end; ++iter) | ||||
{ | { |
}; | }; | ||||
#endif //DOXYGEN_SKIP_PROPERTY | #endif //DOXYGEN_SKIP_PROPERTY | ||||
typedef generator_iterator<_Ty, promise_type> iterator; | |||||
using iterator = generator_iterator<_Ty, promise_type>; | |||||
iterator begin() | iterator begin() | ||||
{ | { |
{ | { | ||||
#endif //DOXYGEN_SKIP_PROPERTY | #endif //DOXYGEN_SKIP_PROPERTY | ||||
/** | /** | ||||
* @brief 提示手工解锁,故相关的lock()函数不再返回scoped_unlock_t。 | |||||
* @brief 提示手工解锁,故相关的lock()函数不再返回batch_unlock_t。 | |||||
*/ | */ | ||||
struct adopt_manual_unlock_t{}; | struct adopt_manual_unlock_t{}; | ||||
/** | /** | ||||
* @brief 提示手工解锁,故相关的lock()函数不再返回scoped_unlock_t。 | |||||
* @brief 提示手工解锁,故相关的lock()函数不再返回batch_unlock_t。 | |||||
*/ | */ | ||||
constexpr adopt_manual_unlock_t adopt_manual_unlock; | constexpr adopt_manual_unlock_t adopt_manual_unlock; | ||||
* @brief 在析构的时候自动解锁mutex_t的辅助类。 | * @brief 在析构的时候自动解锁mutex_t的辅助类。 | ||||
*/ | */ | ||||
template<class... _Mtxs> | template<class... _Mtxs> | ||||
struct [[nodiscard]] scoped_unlock_t; | |||||
struct [[nodiscard]] batch_unlock_t; | |||||
/** | /** | ||||
* @brief 支持递归的锁。 | * @brief 支持递归的锁。 | ||||
/** | /** | ||||
* @brief 在协程中加锁,如果不能立即获得锁,则阻塞当前协程。但不会阻塞当前线程。 | * @brief 在协程中加锁,如果不能立即获得锁,则阻塞当前协程。但不会阻塞当前线程。 | ||||
* @return [co_await] scoped_unlock_t | |||||
* @return [co_await] batch_unlock_t | |||||
*/ | */ | ||||
awaiter/*scoped_unlock_t*/ lock() const noexcept; | |||||
awaiter/*batch_unlock_t*/ lock() const noexcept; | |||||
/** | /** | ||||
* @brief 等同调用 co_await lock()。 | * @brief 等同调用 co_await lock()。 | ||||
* @return [co_await] scoped_unlock_t | |||||
* @return [co_await] batch_unlock_t | |||||
*/ | */ | ||||
awaiter/*scoped_unlock_t*/ operator co_await() const noexcept; | |||||
awaiter/*batch_unlock_t*/ operator co_await() const noexcept; | |||||
/** | /** | ||||
* @brief 在协程中加锁,如果不能立即获得锁,则阻塞当前协程。但不会阻塞当前线程。 | * @brief 在协程中加锁,如果不能立即获得锁,则阻塞当前协程。但不会阻塞当前线程。 | ||||
/** | /** | ||||
* @brief 在协程中,无死锁的批量加锁。不会阻塞当前线程。直到获得所有锁之前,会阻塞当前协程。 | * @brief 在协程中,无死锁的批量加锁。不会阻塞当前线程。直到获得所有锁之前,会阻塞当前协程。 | ||||
* @param mtxs... 需要获得的锁列表。 | * @param mtxs... 需要获得的锁列表。 | ||||
* @return [co_await] scoped_unlock_t | |||||
* @return [co_await] batch_unlock_t | |||||
*/ | */ | ||||
template<class... _Mtxs | template<class... _Mtxs | ||||
#ifndef DOXYGEN_SKIP_PROPERTY | #ifndef DOXYGEN_SKIP_PROPERTY | ||||
, 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>...>> | ||||
#endif //DOXYGEN_SKIP_PROPERTY | #endif //DOXYGEN_SKIP_PROPERTY | ||||
> | > | ||||
static future_t<scoped_unlock_t<_Mtxs...>> lock(_Mtxs&... mtxs); | |||||
static future_t<batch_unlock_t<_Mtxs...>> lock(_Mtxs&... mtxs); | |||||
/** | /** | ||||
* @brief 在协程中,无死锁的批量加锁。不会阻塞当前线程。直到获得所有锁之前,会阻塞当前协程。 | * @brief 在协程中,无死锁的批量加锁。不会阻塞当前线程。直到获得所有锁之前,会阻塞当前协程。 | ||||
* @brief 在非协程中,无死锁的批量加锁。会阻塞当前线程,直到获得所有锁为止。 | * @brief 在非协程中,无死锁的批量加锁。会阻塞当前线程,直到获得所有锁为止。 | ||||
* @param unique_address 代表获得锁的拥有者。 | * @param unique_address 代表获得锁的拥有者。 | ||||
* @param mtxs... 需要获得的锁列表。 | * @param mtxs... 需要获得的锁列表。 | ||||
* @return scoped_unlock_t | |||||
* @return batch_unlock_t | |||||
*/ | */ | ||||
template<class... _Mtxs | template<class... _Mtxs | ||||
#ifndef DOXYGEN_SKIP_PROPERTY | #ifndef DOXYGEN_SKIP_PROPERTY | ||||
, 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>...>> | ||||
#endif //DOXYGEN_SKIP_PROPERTY | #endif //DOXYGEN_SKIP_PROPERTY | ||||
> | > | ||||
static scoped_unlock_t<_Mtxs...> lock(void* unique_address, _Mtxs&... mtxs); | |||||
static batch_unlock_t<_Mtxs...> lock(void* unique_address, _Mtxs&... mtxs); | |||||
/** | /** | ||||
* @brief 在非协程中,无死锁的批量加锁。会阻塞当前线程,直到获得所有锁为止。 | * @brief 在非协程中,无死锁的批量加锁。会阻塞当前线程,直到获得所有锁为止。 | ||||
private: | private: | ||||
struct _MutexAwaitAssembleT; | struct _MutexAwaitAssembleT; | ||||
template<class... _Mtxs> friend struct scoped_unlock_t; | |||||
template<class... _Mtxs> friend struct batch_unlock_t; | |||||
mutex_impl_ptr _mutex; | mutex_impl_ptr _mutex; | ||||
#endif //DOXYGEN_SKIP_PROPERTY | #endif //DOXYGEN_SKIP_PROPERTY |
inline namespace mutex_v2 | inline namespace mutex_v2 | ||||
{ | { | ||||
template<> | template<> | ||||
struct [[nodiscard]] scoped_unlock_t<mutex_t> | |||||
struct [[nodiscard]] batch_unlock_t<mutex_t> | |||||
{ | { | ||||
typedef std::shared_ptr<detail::mutex_v2_impl> mutex_impl_ptr; | typedef std::shared_ptr<detail::mutex_v2_impl> mutex_impl_ptr; | ||||
scoped_unlock_t() | |||||
batch_unlock_t() | |||||
: _owner(nullptr) | : _owner(nullptr) | ||||
{} | {} | ||||
//此函数,应该在try_lock()获得锁后使用 | //此函数,应该在try_lock()获得锁后使用 | ||||
//或者在协程里,由awaiter使用 | //或者在协程里,由awaiter使用 | ||||
scoped_unlock_t(std::adopt_lock_t, void* sch, mutex_impl_ptr mtx) | |||||
batch_unlock_t(std::adopt_lock_t, void* sch, mutex_impl_ptr mtx) | |||||
: _mutex(std::move(mtx)) | : _mutex(std::move(mtx)) | ||||
, _owner(sch) | , _owner(sch) | ||||
{} | {} | ||||
batch_unlock_t(std::adopt_lock_t, void* sch, const mutex_t& mtx) | |||||
: batch_unlock_t(std::adopt_lock, sch, mtx._mutex) | |||||
{} | |||||
/* | |||||
//此函数,适合在非协程里使用 | //此函数,适合在非协程里使用 | ||||
scoped_unlock_t(void* sch, mutex_impl_ptr mtx) | |||||
batch_unlock_t(void* sch, mutex_impl_ptr mtx) | |||||
: _mutex(std::move(mtx)) | : _mutex(std::move(mtx)) | ||||
, _owner(sch) | , _owner(sch) | ||||
{ | { | ||||
_mutex->lock_until_succeed(sch); | _mutex->lock_until_succeed(sch); | ||||
} | } | ||||
scoped_unlock_t(std::adopt_lock_t, void* sch, const mutex_t& mtx) | |||||
: scoped_unlock_t(std::adopt_lock, sch, mtx._mutex) | |||||
{} | |||||
scoped_unlock_t(void* sch, const mutex_t& mtx) | |||||
: scoped_unlock_t(sch, mtx._mutex) | |||||
batch_unlock_t(void* sch, const mutex_t& mtx) | |||||
: batch_unlock_t(sch, mtx._mutex) | |||||
{} | {} | ||||
*/ | |||||
~scoped_unlock_t() | |||||
~batch_unlock_t() | |||||
{ | { | ||||
if (_mutex != nullptr) | if (_mutex != nullptr) | ||||
_mutex->unlock(_owner); | _mutex->unlock(_owner); | ||||
} | } | ||||
} | } | ||||
scoped_unlock_t(const scoped_unlock_t&) = delete; | |||||
scoped_unlock_t& operator = (const scoped_unlock_t&) = delete; | |||||
scoped_unlock_t(scoped_unlock_t&& _Right) = default; | |||||
scoped_unlock_t& operator = (scoped_unlock_t&& _Right) = default; | |||||
batch_unlock_t(const batch_unlock_t&) = delete; | |||||
batch_unlock_t& operator = (const batch_unlock_t&) = delete; | |||||
batch_unlock_t(batch_unlock_t&& _Right) = default; | |||||
batch_unlock_t& operator = (batch_unlock_t&& _Right) = default; | |||||
private: | private: | ||||
mutex_impl_ptr _mutex; | mutex_impl_ptr _mutex; | ||||
void* _owner; | void* _owner; | ||||
{ | { | ||||
return await_suspend2(handler, []{}); | return await_suspend2(handler, []{}); | ||||
} | } | ||||
scoped_unlock_t<mutex_t> await_resume() noexcept | |||||
batch_unlock_t<mutex_t> await_resume() noexcept | |||||
{ | { | ||||
mutex_impl_ptr mtx = _mutex ? _mutex->shared_from_this() : nullptr; | mutex_impl_ptr mtx = _mutex ? _mutex->shared_from_this() : nullptr; | ||||
_mutex = nullptr; | _mutex = nullptr; | ||||
}; | }; | ||||
template<class... _Mtxs> | template<class... _Mtxs> | ||||
struct [[nodiscard]] scoped_unlock_t | |||||
struct [[nodiscard]] batch_unlock_t | |||||
{ | { | ||||
mutex_t::_MutexAwaitAssembleT _MAA; | mutex_t::_MutexAwaitAssembleT _MAA; | ||||
template<class... U> | template<class... U> | ||||
scoped_unlock_t(std::adopt_lock_t, void* sch, U&&... mtxs) | |||||
batch_unlock_t(std::adopt_lock_t, void* sch, U&&... mtxs) | |||||
: _MAA(sch, std::forward<U>(mtxs)...) | : _MAA(sch, std::forward<U>(mtxs)...) | ||||
{} | {} | ||||
~scoped_unlock_t() | |||||
~batch_unlock_t() | |||||
{ | { | ||||
if (_MAA._owner != nullptr) | if (_MAA._owner != nullptr) | ||||
{ | { | ||||
} | } | ||||
} | } | ||||
scoped_unlock_t(const scoped_unlock_t&) = delete; | |||||
scoped_unlock_t& operator = (const scoped_unlock_t&) = delete; | |||||
scoped_unlock_t(scoped_unlock_t&& _Right) = default; | |||||
scoped_unlock_t& operator = (scoped_unlock_t&& _Right) = default; | |||||
batch_unlock_t(const batch_unlock_t&) = delete; | |||||
batch_unlock_t& operator = (const batch_unlock_t&) = delete; | |||||
batch_unlock_t(batch_unlock_t&& _Right) = default; | |||||
batch_unlock_t& operator = (batch_unlock_t&& _Right) = default; | |||||
}; | }; | ||||
template<class... _Mtxs> | template<class... _Mtxs> | ||||
scoped_unlock_t()->scoped_unlock_t<_Mtxs...>; | |||||
batch_unlock_t()->batch_unlock_t<_Mtxs...>; | |||||
template<class... _Mtxs, typename> | template<class... _Mtxs, typename> | ||||
inline future_t<scoped_unlock_t<_Mtxs...>> mutex_t::lock(_Mtxs&... mtxs) | |||||
inline future_t<batch_unlock_t<_Mtxs...>> mutex_t::lock(_Mtxs&... mtxs) | |||||
{ | { | ||||
scoped_unlock_t<_Mtxs...> unlock_guard{ std::adopt_lock, root_state(), mtxs... }; | |||||
batch_unlock_t<_Mtxs...> unlock_guard{ std::adopt_lock, root_state(), mtxs... }; | |||||
co_await detail::mutex_lock_await_lock_impl::_Lock_range(unlock_guard._MAA); | co_await detail::mutex_lock_await_lock_impl::_Lock_range(unlock_guard._MAA); | ||||
co_return std::move(unlock_guard); | co_return std::move(unlock_guard); | ||||
} | } | ||||
} | } | ||||
template<class... _Mtxs, typename> | template<class... _Mtxs, typename> | ||||
inline scoped_unlock_t<_Mtxs...> mutex_t::lock(void* unique_address, _Mtxs&... mtxs) | |||||
inline batch_unlock_t<_Mtxs...> mutex_t::lock(void* unique_address, _Mtxs&... mtxs) | |||||
{ | { | ||||
assert(unique_address != nullptr); | assert(unique_address != nullptr); | ||||
detail::_MutexAddressAssembleT _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); | ||||
scoped_unlock_t<_Mtxs...> su{ std::adopt_lock, unique_address }; | |||||
batch_unlock_t<_Mtxs...> su{ std::adopt_lock, unique_address }; | |||||
su._MAA._mutex = std::move(_MAA._mutex); | su._MAA._mutex = std::move(_MAA._mutex); | ||||
return su; | return su; | ||||
} | } |
#pragma once | #pragma once | ||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
RESUMEF_NS | RESUMEF_NS | ||||
{ | { | ||||
struct local_scheduler; | struct local_scheduler; | ||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
struct scheduler_t : public std::enable_shared_from_this<scheduler_t> | struct scheduler_t : public std::enable_shared_from_this<scheduler_t> | ||||
{ | { | ||||
private: | |||||
using state_sptr = counted_ptr<state_base_t>; | using state_sptr = counted_ptr<state_base_t>; | ||||
using state_vector = std::vector<state_sptr>; | using state_vector = std::vector<state_sptr>; | ||||
private: | |||||
using lock_type = std::recursive_mutex; | |||||
using lock_type = spinlock; | |||||
using task_dictionary_type = std::unordered_map<state_base_t*, std::unique_ptr<task_base_t>>; | using task_dictionary_type = std::unordered_map<state_base_t*, std::unique_ptr<task_base_t>>; | ||||
mutable spinlock _lock_running; | mutable spinlock _lock_running; | ||||
void new_task(task_base_t* task); | void new_task(task_base_t* task); | ||||
//void cancel_all_task_(); | //void cancel_all_task_(); | ||||
public: | public: | ||||
void run_one_batch(); | void run_one_batch(); | ||||
void run_until_notask(); | void run_until_notask(); | ||||
//void break_all(); | //void break_all(); | ||||
template<class _Ty | template<class _Ty | ||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
COMMA_RESUMEF_ENABLE_IF(traits::is_callable_v<_Ty> || traits::is_future_v<_Ty> || traits::is_generator_v<_Ty>) | COMMA_RESUMEF_ENABLE_IF(traits::is_callable_v<_Ty> || traits::is_future_v<_Ty> || traits::is_generator_v<_Ty>) | ||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
> | > | ||||
RESUMEF_REQUIRES(traits::is_callable_v<_Ty> || traits::is_future_v<_Ty> || traits::is_generator_v<_Ty>) | |||||
inline void operator + (_Ty&& t_) | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
RESUMEF_REQUIRES(traits::is_callable_v<_Ty> || traits::is_future_v<_Ty> || traits::is_generator_v<_Ty>) | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
void operator + (_Ty&& t_) | |||||
{ | { | ||||
if constexpr (traits::is_callable_v<_Ty>) | if constexpr (traits::is_callable_v<_Ty>) | ||||
new_task(new ctx_task_t<_Ty>(t_)); | new_task(new ctx_task_t<_Ty>(t_)); | ||||
new_task(new task_t<_Ty>(t_)); | new_task(new task_t<_Ty>(t_)); | ||||
} | } | ||||
inline bool empty() const | |||||
bool empty() const | |||||
{ | { | ||||
scoped_lock<spinlock, spinlock> __guard(_lock_ready, _lock_running); | scoped_lock<spinlock, spinlock> __guard(_lock_ready, _lock_running); | ||||
return _ready_task.empty() && _runing_states.empty() && _timer->empty(); | return _ready_task.empty() && _runing_states.empty() && _timer->empty(); | ||||
} | } | ||||
inline timer_manager* timer() const noexcept | |||||
timer_manager* timer() const noexcept | |||||
{ | { | ||||
return _timer.get(); | return _timer.get(); | ||||
} | } | ||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
void add_generator(state_base_t* sptr); | void add_generator(state_base_t* sptr); | ||||
void del_final(state_base_t* sptr); | void del_final(state_base_t* sptr); | ||||
std::unique_ptr<task_base_t> del_switch(state_base_t* sptr); | std::unique_ptr<task_base_t> del_switch(state_base_t* sptr); | ||||
scheduler_t& operator = (const scheduler_t&) = delete; | scheduler_t& operator = (const scheduler_t&) = delete; | ||||
static scheduler_t g_scheduler; | static scheduler_t g_scheduler; | ||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
}; | }; | ||||
struct local_scheduler | struct local_scheduler | ||||
scheduler_t* _scheduler_ptr; | scheduler_t* _scheduler_ptr; | ||||
#endif | #endif | ||||
}; | }; | ||||
//-------------------------------------------------------------------------------------------------- | |||||
#if !RESUMEF_ENABLE_MULT_SCHEDULER | #if !RESUMEF_ENABLE_MULT_SCHEDULER | ||||
//获得当前线程下的调度器 | //获得当前线程下的调度器 | ||||
inline scheduler_t* this_scheduler() | inline scheduler_t* this_scheduler() | ||||
return &scheduler_t::g_scheduler; | return &scheduler_t::g_scheduler; | ||||
} | } | ||||
#endif | #endif | ||||
//-------------------------------------------------------------------------------------------------- | |||||
} | } |
} | } | ||||
#endif //DOXYGEN_SKIP_PROPERTY | #endif //DOXYGEN_SKIP_PROPERTY | ||||
// class with destructor that unlocks mutexes | |||||
template<class _Ty, class _Cont = std::vector<_Ty>, class _Assemble = detail::_LockVectorAssembleT<_Ty, _Cont>> | template<class _Ty, class _Cont = std::vector<_Ty>, class _Assemble = detail::_LockVectorAssembleT<_Ty, _Cont>> | ||||
class scoped_lock_range { // class with destructor that unlocks mutexes | |||||
class batch_lock_t | |||||
{ | |||||
public: | public: | ||||
explicit scoped_lock_range(_Cont& locks_) | |||||
explicit batch_lock_t(_Cont& locks_) | |||||
: _LkN(&locks_) | : _LkN(&locks_) | ||||
, _LA(*_LkN) | , _LA(*_LkN) | ||||
{ | { | ||||
detail::scoped_lock_range_lock_impl::_Lock_range(_LA); | detail::scoped_lock_range_lock_impl::_Lock_range(_LA); | ||||
} | } | ||||
explicit scoped_lock_range(_Cont& locks_, _Assemble& la_) | |||||
explicit batch_lock_t(_Cont& locks_, _Assemble& la_) | |||||
: _LkN(&locks_) | : _LkN(&locks_) | ||||
, _LA(la_) | , _LA(la_) | ||||
{ | { | ||||
detail::scoped_lock_range_lock_impl::_Lock_range(_LA); | detail::scoped_lock_range_lock_impl::_Lock_range(_LA); | ||||
} | } | ||||
explicit scoped_lock_range(std::adopt_lock_t, _Cont& locks_) | |||||
explicit batch_lock_t(std::adopt_lock_t, _Cont& locks_) | |||||
: _LkN(&locks_) | : _LkN(&locks_) | ||||
, _LA(*_LkN) | , _LA(*_LkN) | ||||
{ // construct but don't lock | { // construct but don't lock | ||||
} | } | ||||
explicit scoped_lock_range(std::adopt_lock_t, _Cont& locks_, _Assemble& la_) | |||||
explicit batch_lock_t(std::adopt_lock_t, _Cont& locks_, _Assemble& la_) | |||||
: _LkN(&locks_) | : _LkN(&locks_) | ||||
, _LA(la_) | , _LA(la_) | ||||
{ // construct but don't lock | { // construct but don't lock | ||||
} | } | ||||
~scoped_lock_range() noexcept | |||||
~batch_lock_t() noexcept | |||||
{ | { | ||||
if (_LkN != nullptr) | if (_LkN != nullptr) | ||||
detail::scoped_lock_range_lock_impl::_Unlock_locks(0, (int)_LA.size(), _LA); | detail::scoped_lock_range_lock_impl::_Unlock_locks(0, (int)_LA.size(), _LA); | ||||
} | } | ||||
} | } | ||||
scoped_lock_range(const scoped_lock_range&) = delete; | |||||
scoped_lock_range& operator=(const scoped_lock_range&) = delete; | |||||
batch_lock_t(const batch_lock_t&) = delete; | |||||
batch_lock_t& operator=(const batch_lock_t&) = delete; | |||||
scoped_lock_range(scoped_lock_range&& _Right) | |||||
batch_lock_t(batch_lock_t&& _Right) | |||||
: _LkN(_Right._LkN) | : _LkN(_Right._LkN) | ||||
, _LA(std::move(_Right._LA)) | , _LA(std::move(_Right._LA)) | ||||
{ | { | ||||
_Right._LkN = nullptr; | _Right._LkN = nullptr; | ||||
} | } | ||||
scoped_lock_range& operator=(scoped_lock_range&& _Right) | |||||
batch_lock_t& operator=(batch_lock_t&& _Right) | |||||
{ | { | ||||
if (this != &_Right) | if (this != &_Right) | ||||
{ | { |
for (size_t i = 0; i < N / 2; ++i) | for (size_t i = 0; i < N / 2; ++i) | ||||
{ | { | ||||
{ | { | ||||
scoped_unlock_t _locker = co_await g_lock.lock(); //_locker析构后,会调用对应的unlock()函数。 | |||||
batch_unlock_t _locker = co_await g_lock.lock(); //_locker析构后,会调用对应的unlock()函数。 | |||||
--g_counter; | --g_counter; | ||||
std::cout << "pop :" << g_counter << " on " << idx << std::endl; | std::cout << "pop :" << g_counter << " on " << idx << std::endl; | ||||
co_await 50ms; | co_await 50ms; | ||||
scoped_unlock_t _locker_2 = co_await g_lock; | |||||
batch_unlock_t _locker_2 = co_await g_lock; | |||||
--g_counter; | --g_counter; | ||||
std::cout << "pop :" << g_counter << " on " << idx << std::endl; | std::cout << "pop :" << g_counter << " on " << idx << std::endl; | ||||
for (size_t i = 0; i < N; ++i) | for (size_t i = 0; i < N; ++i) | ||||
{ | { | ||||
{ | { | ||||
scoped_unlock_t _locker = co_await g_lock.lock(); | |||||
batch_unlock_t _locker = co_await g_lock.lock(); | |||||
++g_counter; | ++g_counter; | ||||
std::cout << "push:" << g_counter << " on " << idx << std::endl; | std::cout << "push:" << g_counter << " on " << idx << std::endl; | ||||
{ | { | ||||
if (g_lock.try_lock_for(500ms, &provide_unique_address)) | if (g_lock.try_lock_for(500ms, &provide_unique_address)) | ||||
{ | { | ||||
scoped_unlock_t _locker(std::adopt_lock, &provide_unique_address, g_lock); | |||||
batch_unlock_t _locker(std::adopt_lock, &provide_unique_address, g_lock); | |||||
++g_counter; | ++g_counter; | ||||
std::cout << "push:" << g_counter << " on " << idx << std::endl; | std::cout << "push:" << g_counter << " on " << idx << std::endl; | ||||
{ | { | ||||
for (int i = 0; i < 10000; ++i) | for (int i = 0; i < 10000; ++i) | ||||
{ | { | ||||
scoped_unlock_t __lockers = co_await mutex_t::lock(a, b, c); | |||||
batch_unlock_t __lockers = co_await mutex_t::lock(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()); |