#pragma once | #pragma once | ||||
#define LIB_RESUMEF_VERSION 20700 // 2.7.0 | |||||
#define LIB_RESUMEF_VERSION 20800 // 2.8.0 | |||||
#if defined(RESUMEF_MODULE_EXPORT) | #if defined(RESUMEF_MODULE_EXPORT) | ||||
#define RESUMEF_NS export namespace resumef | #define RESUMEF_NS export namespace resumef |
unlock_more, // unlock 次数多余lock次数 | unlock_more, // unlock 次数多余lock次数 | ||||
read_before_write, // 0容量的channel,先读后写 | read_before_write, // 0容量的channel,先读后写 | ||||
timer_canceled, // 定时器被意外取消 | timer_canceled, // 定时器被意外取消 | ||||
not_await_lock, // 没有在协程中使用co_await等待lock结果 | |||||
max__ | max__ | ||||
}; | }; |
#pragma once | #pragma once | ||||
RESUMEF_NS | |||||
{ | |||||
namespace detail | |||||
{ | |||||
struct mutex_impl; | |||||
typedef ::resumef::detail::_awaker<mutex_impl> mutex_awaker; | |||||
typedef std::shared_ptr<mutex_awaker> mutex_awaker_ptr; | |||||
struct mutex_impl : public std::enable_shared_from_this<mutex_impl> | |||||
{ | |||||
private: | |||||
//typedef spinlock lock_type; | |||||
typedef std::recursive_mutex lock_type; | |||||
std::list<mutex_awaker_ptr> _awakes; | |||||
mutex_awaker_ptr _owner; | |||||
lock_type _lock; | |||||
public: | |||||
mutex_impl(); | |||||
//如果已经触发了awaker,则返回true | |||||
bool lock_(const mutex_awaker_ptr& awaker); | |||||
bool try_lock_(const mutex_awaker_ptr& awaker); | |||||
void unlock(); | |||||
template<class callee_t, class dummy_t = std::enable_if<!std::is_same<std::remove_cv_t<callee_t>, mutex_awaker_ptr>::value>> | |||||
decltype(auto) lock(callee_t&& awaker, dummy_t* dummy_ = nullptr) | |||||
{ | |||||
(void)dummy_; | |||||
return lock_(std::make_shared<mutex_awaker>(std::forward<callee_t>(awaker))); | |||||
} | |||||
private: | |||||
mutex_impl(const mutex_impl&) = delete; | |||||
mutex_impl(mutex_impl&&) = delete; | |||||
mutex_impl& operator = (const mutex_impl&) = delete; | |||||
mutex_impl& operator = (mutex_impl&&) = delete; | |||||
}; | |||||
} | |||||
struct mutex_t | |||||
{ | |||||
typedef std::shared_ptr<detail::mutex_impl> lock_impl_ptr; | |||||
typedef std::weak_ptr<detail::mutex_impl> lock_impl_wptr; | |||||
typedef std::chrono::system_clock clock_type; | |||||
private: | |||||
lock_impl_ptr _locker; | |||||
public: | |||||
mutex_t(); | |||||
void unlock() const | |||||
{ | |||||
_locker->unlock(); | |||||
} | |||||
future_t<bool> lock() const; | |||||
bool try_lock() const; | |||||
/* | |||||
template<class _Rep, class _Period> | |||||
awaitable_t<bool> | |||||
try_lock_for(const std::chrono::duration<_Rep, _Period> & dt) const | |||||
{ | |||||
return try_lock_for_(std::chrono::duration_cast<clock_type::duration>(dt)); | |||||
} | |||||
template<class _Clock, class _Duration> | |||||
awaitable_t<bool> | |||||
try_lock_until(const std::chrono::time_point<_Clock, _Duration> & tp) const | |||||
{ | |||||
return try_lock_until_(std::chrono::time_point_cast<clock_type::duration>(tp)); | |||||
} | |||||
*/ | |||||
mutex_t(const mutex_t&) = default; | |||||
mutex_t(mutex_t&&) = default; | |||||
mutex_t& operator = (const mutex_t&) = default; | |||||
mutex_t& operator = (mutex_t&&) = default; | |||||
private: | |||||
inline future_t<bool> try_lock_for_(const clock_type::duration& dt) const | |||||
{ | |||||
return try_lock_until_(clock_type::now() + dt); | |||||
} | |||||
future_t<bool> try_lock_until_(const clock_type::time_point& tp) const; | |||||
}; | |||||
} | |||||
#include "mutex_v1.h" | |||||
#include "mutex_v2.h" | |||||
#include "mutex_v2.inl" |
#include "../librf.h" | |||||
RESUMEF_NS | |||||
{ | |||||
namespace detail | |||||
{ | |||||
mutex_impl::mutex_impl() | |||||
{ | |||||
} | |||||
void mutex_impl::unlock() | |||||
{ | |||||
scoped_lock<lock_type> lock_(this->_lock); | |||||
if (_owner != nullptr) | |||||
{ | |||||
for (auto iter = _awakes.begin(); iter != _awakes.end(); ) | |||||
{ | |||||
auto awaker = *iter; | |||||
iter = _awakes.erase(iter); | |||||
if (awaker->awake(this, 1)) | |||||
{ | |||||
_owner = awaker; | |||||
break; | |||||
} | |||||
} | |||||
if (_awakes.size() == 0) | |||||
{ | |||||
_owner = nullptr; | |||||
} | |||||
} | |||||
} | |||||
bool mutex_impl::lock_(const mutex_awaker_ptr & awaker) | |||||
{ | |||||
assert(awaker); | |||||
scoped_lock<lock_type> lock_(this->_lock); | |||||
if (_owner == nullptr) | |||||
{ | |||||
_owner = awaker; | |||||
awaker->awake(this, 1); | |||||
return true; | |||||
} | |||||
else | |||||
{ | |||||
_awakes.push_back(awaker); | |||||
return false; | |||||
} | |||||
} | |||||
bool mutex_impl::try_lock_(const mutex_awaker_ptr & awaker) | |||||
{ | |||||
assert(awaker); | |||||
scoped_lock<lock_type> lock_(this->_lock); | |||||
if (_owner == nullptr) | |||||
{ | |||||
_owner = awaker; | |||||
return true; | |||||
} | |||||
else | |||||
{ | |||||
return false; | |||||
} | |||||
} | |||||
} | |||||
mutex_t::mutex_t() | |||||
: _locker(std::make_shared<detail::mutex_impl>()) | |||||
{ | |||||
} | |||||
future_t<bool> mutex_t::lock() const | |||||
{ | |||||
awaitable_t<bool> awaitable; | |||||
auto awaker = std::make_shared<detail::mutex_awaker>( | |||||
[st = awaitable._state](detail::mutex_impl * e) -> bool | |||||
{ | |||||
st->set_value(e ? true : false); | |||||
return true; | |||||
}); | |||||
_locker->lock_(awaker); | |||||
return awaitable.get_future(); | |||||
} | |||||
bool mutex_t::try_lock() const | |||||
{ | |||||
auto dummy_awaker = std::make_shared<detail::mutex_awaker>( | |||||
[](detail::mutex_impl * ) -> bool | |||||
{ | |||||
return true; | |||||
}); | |||||
return _locker->try_lock_(dummy_awaker); | |||||
} | |||||
future_t<bool> mutex_t::try_lock_until_(const clock_type::time_point & tp) const | |||||
{ | |||||
awaitable_t<bool> awaitable; | |||||
auto awaker = std::make_shared<detail::mutex_awaker>( | |||||
[st = awaitable._state](detail::mutex_impl * e) -> bool | |||||
{ | |||||
st->set_value(e ? true : false); | |||||
return true; | |||||
}); | |||||
_locker->lock_(awaker); | |||||
(void)this_scheduler()->timer()->add(tp, | |||||
[awaker](bool ) | |||||
{ | |||||
awaker->awake(nullptr, 1); | |||||
}); | |||||
return awaitable.get_future(); | |||||
} | |||||
} | |||||
#include "../librf.h" | |||||
RESUMEF_NS | |||||
{ | |||||
namespace detail | |||||
{ | |||||
mutex_impl::mutex_impl() | |||||
{ | |||||
} | |||||
void mutex_impl::unlock() | |||||
{ | |||||
scoped_lock<lock_type> lock_(this->_lock); | |||||
if (_owner != nullptr) | |||||
{ | |||||
for (auto iter = _awakes.begin(); iter != _awakes.end(); ) | |||||
{ | |||||
auto awaker = *iter; | |||||
iter = _awakes.erase(iter); | |||||
if (awaker->awake(this, 1)) | |||||
{ | |||||
_owner = awaker; | |||||
break; | |||||
} | |||||
} | |||||
if (_awakes.size() == 0) | |||||
{ | |||||
_owner = nullptr; | |||||
} | |||||
} | |||||
} | |||||
bool mutex_impl::lock_(const mutex_awaker_ptr& awaker) | |||||
{ | |||||
assert(awaker); | |||||
scoped_lock<lock_type> lock_(this->_lock); | |||||
if (_owner == nullptr) | |||||
{ | |||||
_owner = awaker; | |||||
awaker->awake(this, 1); | |||||
return true; | |||||
} | |||||
else | |||||
{ | |||||
_awakes.push_back(awaker); | |||||
return false; | |||||
} | |||||
} | |||||
bool mutex_impl::try_lock_(const mutex_awaker_ptr& awaker) | |||||
{ | |||||
assert(awaker); | |||||
scoped_lock<lock_type> lock_(this->_lock); | |||||
if (_owner == nullptr) | |||||
{ | |||||
_owner = awaker; | |||||
return true; | |||||
} | |||||
else | |||||
{ | |||||
return false; | |||||
} | |||||
} | |||||
} | |||||
namespace mutex_v1 | |||||
{ | |||||
mutex_t::mutex_t() | |||||
: _locker(std::make_shared<detail::mutex_impl>()) | |||||
{ | |||||
} | |||||
future_t<bool> mutex_t::lock() const | |||||
{ | |||||
awaitable_t<bool> awaitable; | |||||
auto awaker = std::make_shared<detail::mutex_awaker>( | |||||
[st = awaitable._state](detail::mutex_impl* e) -> bool | |||||
{ | |||||
st->set_value(e ? true : false); | |||||
return true; | |||||
}); | |||||
_locker->lock_(awaker); | |||||
return awaitable.get_future(); | |||||
} | |||||
bool mutex_t::try_lock() const | |||||
{ | |||||
auto dummy_awaker = std::make_shared<detail::mutex_awaker>( | |||||
[](detail::mutex_impl*) -> bool | |||||
{ | |||||
return true; | |||||
}); | |||||
return _locker->try_lock_(dummy_awaker); | |||||
} | |||||
future_t<bool> mutex_t::try_lock_until_(const clock_type::time_point& tp) const | |||||
{ | |||||
awaitable_t<bool> awaitable; | |||||
auto awaker = std::make_shared<detail::mutex_awaker>( | |||||
[st = awaitable._state](detail::mutex_impl* e) -> bool | |||||
{ | |||||
st->set_value(e ? true : false); | |||||
return true; | |||||
}); | |||||
_locker->lock_(awaker); | |||||
(void)this_scheduler()->timer()->add(tp, | |||||
[awaker](bool) | |||||
{ | |||||
awaker->awake(nullptr, 1); | |||||
}); | |||||
return awaitable.get_future(); | |||||
} | |||||
} | |||||
} |
#pragma once | |||||
RESUMEF_NS | |||||
{ | |||||
namespace detail | |||||
{ | |||||
struct mutex_impl; | |||||
typedef ::resumef::detail::_awaker<mutex_impl> mutex_awaker; | |||||
typedef std::shared_ptr<mutex_awaker> mutex_awaker_ptr; | |||||
struct mutex_impl : public std::enable_shared_from_this<mutex_impl> | |||||
{ | |||||
private: | |||||
//typedef spinlock lock_type; | |||||
typedef std::recursive_mutex lock_type; | |||||
std::list<mutex_awaker_ptr> _awakes; | |||||
mutex_awaker_ptr _owner; | |||||
lock_type _lock; | |||||
public: | |||||
mutex_impl(); | |||||
//如果已经触发了awaker,则返回true | |||||
bool lock_(const mutex_awaker_ptr& awaker); | |||||
bool try_lock_(const mutex_awaker_ptr& awaker); | |||||
void unlock(); | |||||
template<class callee_t, class dummy_t = std::enable_if<!std::is_same<std::remove_cv_t<callee_t>, mutex_awaker_ptr>::value>> | |||||
decltype(auto) lock(callee_t&& awaker, dummy_t* dummy_ = nullptr) | |||||
{ | |||||
(void)dummy_; | |||||
return lock_(std::make_shared<mutex_awaker>(std::forward<callee_t>(awaker))); | |||||
} | |||||
private: | |||||
mutex_impl(const mutex_impl&) = delete; | |||||
mutex_impl(mutex_impl&&) = delete; | |||||
mutex_impl& operator = (const mutex_impl&) = delete; | |||||
mutex_impl& operator = (mutex_impl&&) = delete; | |||||
}; | |||||
} | |||||
namespace mutex_v1 | |||||
{ | |||||
struct mutex_t | |||||
{ | |||||
typedef std::shared_ptr<detail::mutex_impl> lock_impl_ptr; | |||||
typedef std::weak_ptr<detail::mutex_impl> lock_impl_wptr; | |||||
typedef std::chrono::system_clock clock_type; | |||||
private: | |||||
lock_impl_ptr _locker; | |||||
public: | |||||
mutex_t(); | |||||
void unlock() const | |||||
{ | |||||
_locker->unlock(); | |||||
} | |||||
future_t<bool> lock() const; | |||||
bool try_lock() const; | |||||
/* | |||||
template<class _Rep, class _Period> | |||||
awaitable_t<bool> | |||||
try_lock_for(const std::chrono::duration<_Rep, _Period> & dt) const | |||||
{ | |||||
return try_lock_for_(std::chrono::duration_cast<clock_type::duration>(dt)); | |||||
} | |||||
template<class _Clock, class _Duration> | |||||
awaitable_t<bool> | |||||
try_lock_until(const std::chrono::time_point<_Clock, _Duration> & tp) const | |||||
{ | |||||
return try_lock_until_(std::chrono::time_point_cast<clock_type::duration>(tp)); | |||||
} | |||||
*/ | |||||
mutex_t(const mutex_t&) = default; | |||||
mutex_t(mutex_t&&) = default; | |||||
mutex_t& operator = (const mutex_t&) = default; | |||||
mutex_t& operator = (mutex_t&&) = default; | |||||
private: | |||||
inline future_t<bool> try_lock_for_(const clock_type::duration& dt) const | |||||
{ | |||||
return try_lock_until_(clock_type::now() + dt); | |||||
} | |||||
future_t<bool> try_lock_until_(const clock_type::time_point& tp) const; | |||||
}; | |||||
} | |||||
} |
#include "../librf.h" | |||||
RESUMEF_NS | |||||
{ | |||||
namespace detail | |||||
{ | |||||
void state_mutex_t::resume() | |||||
{ | |||||
coroutine_handle<> handler = _coro; | |||||
if (handler) | |||||
{ | |||||
_coro = nullptr; | |||||
_scheduler->del_final(this); | |||||
handler.resume(); | |||||
} | |||||
} | |||||
bool state_mutex_t::has_handler() const noexcept | |||||
{ | |||||
return (bool)_coro; | |||||
} | |||||
state_base_t* state_mutex_t::get_parent() const noexcept | |||||
{ | |||||
return _root; | |||||
} | |||||
bool state_mutex_t::on_notify() | |||||
{ | |||||
assert(this->_scheduler != nullptr); | |||||
if (this->_coro) | |||||
{ | |||||
this->_scheduler->add_generator(this); | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
void mutex_v2_impl::lock_until_succeed(void* sch) | |||||
{ | |||||
assert(sch != nullptr); | |||||
for (;;) | |||||
{ | |||||
if (try_lock(sch)) | |||||
break; | |||||
std::this_thread::yield(); | |||||
} | |||||
} | |||||
bool mutex_v2_impl::try_lock(void* sch) noexcept | |||||
{ | |||||
scoped_lock<detail::mutex_v2_impl::lock_type> lock_(_lock); | |||||
return try_lock_lockless(sch); | |||||
} | |||||
bool mutex_v2_impl::try_lock_lockless(void* sch) noexcept | |||||
{ | |||||
void* oldValue = _owner.load(std::memory_order_relaxed); | |||||
if (oldValue == nullptr || oldValue == sch) | |||||
{ | |||||
_owner.store(sch, std::memory_order_relaxed); | |||||
_counter.fetch_add(1, std::memory_order_relaxed); | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
bool mutex_v2_impl::unlock(void* sch) | |||||
{ | |||||
scoped_lock<lock_type> lock_(_lock); | |||||
void* oldValue = _owner.load(std::memory_order_relaxed); | |||||
if (oldValue == sch) | |||||
{ | |||||
if (_counter.fetch_sub(1, std::memory_order_relaxed) == 1) | |||||
{ | |||||
if (!_wait_awakes.empty()) | |||||
{ | |||||
state_mutex_ptr state = _wait_awakes.front(); | |||||
_wait_awakes.pop_front(); | |||||
//锁定状态转移到新的state上 | |||||
_owner.store(state->get_root(), std::memory_order_relaxed); | |||||
_counter.fetch_add(1, std::memory_order_relaxed); | |||||
state->on_notify(); | |||||
} | |||||
else | |||||
{ | |||||
_owner.store(nullptr, std::memory_order_relaxed); | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
void mutex_v2_impl::add_wait_list_lockless(state_mutex_t* state) | |||||
{ | |||||
assert(state != nullptr); | |||||
_wait_awakes.push_back(state); | |||||
} | |||||
} | |||||
inline namespace mutex_v2 | |||||
{ | |||||
mutex_t::mutex_t() | |||||
: _mutex(std::make_shared<detail::mutex_v2_impl>()) | |||||
{ | |||||
} | |||||
mutex_t::mutex_t(std::adopt_lock_t) noexcept | |||||
{ | |||||
} | |||||
mutex_t::~mutex_t() noexcept | |||||
{ | |||||
} | |||||
} | |||||
} |
#pragma once | |||||
RESUMEF_NS | |||||
{ | |||||
namespace detail | |||||
{ | |||||
struct mutex_v2_impl; | |||||
} | |||||
inline namespace mutex_v2 | |||||
{ | |||||
struct scoped_lock_mutex_t; | |||||
struct mutex_t | |||||
{ | |||||
typedef std::shared_ptr<detail::mutex_v2_impl> mutex_impl_ptr; | |||||
typedef std::chrono::system_clock clock_type; | |||||
mutex_t(); | |||||
mutex_t(std::adopt_lock_t) noexcept; | |||||
~mutex_t() noexcept; | |||||
struct [[nodiscard]] awaiter; | |||||
awaiter lock() const noexcept; | |||||
scoped_lock_mutex_t lock(scheduler_t* sch) const noexcept; | |||||
bool try_lock(scheduler_t* sch) const noexcept; | |||||
void unlock(scheduler_t* sch) const noexcept; | |||||
mutex_t(const mutex_t&) = default; | |||||
mutex_t(mutex_t&&) = default; | |||||
mutex_t& operator = (const mutex_t&) = default; | |||||
mutex_t& operator = (mutex_t&&) = default; | |||||
private: | |||||
friend struct scoped_lock_mutex_t; | |||||
mutex_impl_ptr _mutex; | |||||
}; | |||||
} | |||||
} |
#pragma once | |||||
RESUMEF_NS | |||||
{ | |||||
namespace detail | |||||
{ | |||||
struct state_mutex_t : public state_base_t | |||||
{ | |||||
virtual void resume() override; | |||||
virtual bool has_handler() const noexcept override; | |||||
virtual state_base_t* get_parent() const noexcept override; | |||||
bool on_notify(); | |||||
inline scheduler_t* get_scheduler() const noexcept | |||||
{ | |||||
return _scheduler; | |||||
} | |||||
inline void on_await_suspend(coroutine_handle<> handler, scheduler_t* sch, state_base_t* root) noexcept | |||||
{ | |||||
this->_scheduler = sch; | |||||
this->_coro = handler; | |||||
this->_root = root; | |||||
} | |||||
private: | |||||
state_base_t* _root; | |||||
//friend mutex_v2::mutex_t; | |||||
}; | |||||
//做成递归锁? | |||||
struct mutex_v2_impl : public std::enable_shared_from_this<mutex_v2_impl> | |||||
{ | |||||
mutex_v2_impl() {} | |||||
inline void* owner() const noexcept | |||||
{ | |||||
return _owner.load(std::memory_order_relaxed); | |||||
} | |||||
bool try_lock(void* sch) noexcept; //内部加锁 | |||||
bool unlock(void* sch); //内部加锁 | |||||
void lock_until_succeed(void* sch); //内部加锁 | |||||
public: | |||||
static constexpr bool USE_SPINLOCK = true; | |||||
using lock_type = std::conditional_t<USE_SPINLOCK, spinlock, std::recursive_mutex>; | |||||
using state_mutex_ptr = counted_ptr<state_mutex_t>; | |||||
using wait_queue_type = std::list<state_mutex_ptr>; | |||||
bool try_lock_lockless(void* sch) noexcept; //内部不加锁,加锁由外部来进行 | |||||
void add_wait_list_lockless(state_mutex_t* state); //内部不加锁,加锁由外部来进行 | |||||
lock_type _lock; //保证访问本对象是线程安全的 | |||||
private: | |||||
std::atomic<void*> _owner = nullptr; //锁标记 | |||||
std::atomic<intptr_t> _counter = 0; //递归锁的次数 | |||||
wait_queue_type _wait_awakes; //等待队列 | |||||
// No copying/moving | |||||
mutex_v2_impl(const mutex_v2_impl&) = delete; | |||||
mutex_v2_impl(mutex_v2_impl&&) = delete; | |||||
mutex_v2_impl& operator=(const mutex_v2_impl&) = delete; | |||||
mutex_v2_impl& operator=(mutex_v2_impl&&) = delete; | |||||
}; | |||||
} | |||||
inline namespace mutex_v2 | |||||
{ | |||||
struct scoped_lock_mutex_t | |||||
{ | |||||
typedef std::shared_ptr<detail::mutex_v2_impl> mutex_impl_ptr; | |||||
//此函数,应该在try_lock()获得锁后使用 | |||||
//或者在协程里,由awaiter使用 | |||||
scoped_lock_mutex_t(std::adopt_lock_t, detail::mutex_v2_impl* mtx, void* sch) | |||||
: _mutex(mtx->shared_from_this()) | |||||
, _owner(sch) | |||||
{} | |||||
//此函数,适合在非协程里使用 | |||||
scoped_lock_mutex_t(detail::mutex_v2_impl* mtx, void* sch) | |||||
: _mutex(mtx->shared_from_this()) | |||||
, _owner(sch) | |||||
{ | |||||
if (sch != nullptr) | |||||
_mutex->lock_until_succeed(sch); | |||||
} | |||||
scoped_lock_mutex_t(std::adopt_lock_t, const mutex_t& mtx, void* sch) | |||||
: scoped_lock_mutex_t(std::adopt_lock, mtx._mutex.get(), sch) | |||||
{} | |||||
scoped_lock_mutex_t(const mutex_t& mtx, void* sch) | |||||
: scoped_lock_mutex_t(mtx._mutex.get(), sch) | |||||
{} | |||||
~scoped_lock_mutex_t() | |||||
{ | |||||
if (_mutex != nullptr) | |||||
_mutex->unlock(_owner); | |||||
} | |||||
inline void unlock() noexcept | |||||
{ | |||||
if (_mutex != nullptr) | |||||
{ | |||||
_mutex->unlock(_owner); | |||||
_mutex = nullptr; | |||||
} | |||||
} | |||||
scoped_lock_mutex_t(const scoped_lock_mutex_t&) = delete; | |||||
scoped_lock_mutex_t& operator = (const scoped_lock_mutex_t&) = delete; | |||||
scoped_lock_mutex_t(scoped_lock_mutex_t&&) = default; | |||||
scoped_lock_mutex_t& operator = (scoped_lock_mutex_t&&) = default; | |||||
private: | |||||
mutex_impl_ptr _mutex; | |||||
void* _owner; | |||||
}; | |||||
struct [[nodiscard]] mutex_t::awaiter | |||||
{ | |||||
awaiter(detail::mutex_v2_impl* evt) noexcept | |||||
: _mutex(evt) | |||||
{ | |||||
} | |||||
~awaiter() noexcept(false) | |||||
{ | |||||
assert(_mutex == nullptr); | |||||
if (_mutex != nullptr) | |||||
{ | |||||
throw lock_exception(error_code::not_await_lock); | |||||
} | |||||
} | |||||
bool await_ready() noexcept | |||||
{ | |||||
return false; | |||||
} | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
bool await_suspend(coroutine_handle<_PromiseT> handler) | |||||
{ | |||||
_PromiseT& promise = handler.promise(); | |||||
auto* parent = promise.get_state(); | |||||
_root = parent->get_root(); | |||||
scoped_lock<detail::mutex_v2_impl::lock_type> lock_(_mutex->_lock); | |||||
if (_mutex->try_lock_lockless(_root)) | |||||
return false; | |||||
_state = new detail::state_mutex_t(); | |||||
(void)_state->on_await_suspend(handler, parent->get_scheduler(), _root); | |||||
_mutex->add_wait_list_lockless(_state.get()); | |||||
return true; | |||||
} | |||||
scoped_lock_mutex_t await_resume() noexcept | |||||
{ | |||||
detail::mutex_v2_impl* mtx = _mutex; | |||||
_mutex = nullptr; | |||||
return { std::adopt_lock, mtx, _root }; | |||||
} | |||||
protected: | |||||
detail::mutex_v2_impl* _mutex; | |||||
counted_ptr<detail::state_mutex_t> _state; | |||||
state_base_t* _root = nullptr; | |||||
}; | |||||
inline mutex_t::awaiter mutex_t::lock() const noexcept | |||||
{ | |||||
return { _mutex.get() }; | |||||
} | |||||
inline scoped_lock_mutex_t mutex_t::lock(scheduler_t* sch) const noexcept | |||||
{ | |||||
if (sch != nullptr) | |||||
_mutex->lock_until_succeed(sch); | |||||
return { std::adopt_lock, _mutex.get(), sch }; | |||||
} | |||||
inline bool mutex_t::try_lock(scheduler_t* sch) const noexcept | |||||
{ | |||||
if (sch == nullptr) | |||||
return false; | |||||
return _mutex->try_lock(sch); | |||||
} | |||||
inline void mutex_t::unlock(scheduler_t* sch) const noexcept | |||||
{ | |||||
assert(sch != nullptr); | |||||
_mutex->unlock(sch); | |||||
} | |||||
} | |||||
} |
"unlock_more", | "unlock_more", | ||||
"read_before_write", | "read_before_write", | ||||
"timer_canceled", | "timer_canceled", | ||||
"not_await_lock", | |||||
}; | }; | ||||
char sz_future_error_buffer[256]; | char sz_future_error_buffer[256]; |
static const int FREE_VALUE = 0; | static const int FREE_VALUE = 0; | ||||
static const int LOCKED_VALUE = 1; | static const int LOCKED_VALUE = 1; | ||||
volatile std::atomic<int> lck; | |||||
std::atomic<int> lck; | |||||
#if _DEBUG | #if _DEBUG | ||||
std::thread::id owner_thread_id; | std::thread::id owner_thread_id; | ||||
#endif | #endif |
{ | { | ||||
delete this; | delete this; | ||||
} | } | ||||
state_base_t* state_base_t::get_parent() const noexcept | |||||
{ | |||||
return nullptr; | |||||
} | |||||
void state_future_t::destroy_deallocate() | void state_future_t::destroy_deallocate() | ||||
{ | { | ||||
return true; | return true; | ||||
} | } | ||||
state_base_t* state_future_t::get_parent() const noexcept | |||||
{ | |||||
return _parent; | |||||
} | |||||
void state_future_t::resume() | void state_future_t::resume() | ||||
{ | { | ||||
std::unique_lock<lock_type> __guard(_mtx); | std::unique_lock<lock_type> __guard(_mtx); |
public: | public: | ||||
virtual void resume() = 0; | virtual void resume() = 0; | ||||
virtual bool has_handler() const noexcept = 0; | virtual bool has_handler() const noexcept = 0; | ||||
virtual state_base_t* get_parent() const noexcept; | |||||
void set_scheduler(scheduler_t* sch) | void set_scheduler(scheduler_t* sch) | ||||
{ | { | ||||
{ | { | ||||
return _coro; | return _coro; | ||||
} | } | ||||
state_base_t* get_root() const noexcept | |||||
{ | |||||
state_base_t* root = const_cast<state_base_t*>(this); | |||||
state_base_t* next = root->get_parent(); | |||||
while (next != nullptr) | |||||
{ | |||||
root = next; | |||||
next = next->get_parent(); | |||||
} | |||||
return root; | |||||
} | |||||
}; | }; | ||||
struct state_generator_t : public state_base_t | struct state_generator_t : public state_base_t | ||||
virtual void destroy_deallocate() override; | virtual void destroy_deallocate() override; | ||||
virtual void resume() override; | virtual void resume() override; | ||||
virtual bool has_handler() const noexcept override; | virtual bool has_handler() const noexcept override; | ||||
virtual state_base_t* get_parent() const noexcept override; | |||||
inline bool is_ready() const noexcept | inline bool is_ready() const noexcept | ||||
{ | { | ||||
//msvc认为是constexpr表达式(不写还给警告),然而,clang不这么认为。 | //msvc认为是constexpr表达式(不写还给警告),然而,clang不这么认为。 | ||||
return _parent ? _parent->get_scheduler() : _scheduler; | return _parent ? _parent->get_scheduler() : _scheduler; | ||||
} | } | ||||
inline state_base_t * get_parent() const noexcept | |||||
{ | |||||
return _parent; | |||||
} | |||||
inline uint32_t get_alloc_size() const noexcept | inline uint32_t get_alloc_size() const noexcept | ||||
{ | { | ||||
return _alloc_size; | return _alloc_size; |
for (size_t i = 0; i < 10; ++i) | for (size_t i = 0; i < 10; ++i) | ||||
{ | { | ||||
co_await resumf_guard_lock(g_lock); | |||||
auto _locker = co_await g_lock.lock(); | |||||
if (g_queue.size() > 0) | if (g_queue.size() > 0) | ||||
{ | { | ||||
} | } | ||||
} | } | ||||
future_t<> test_mutex_push() | |||||
future_t<> test_mutex_push(size_t idx) | |||||
{ | { | ||||
using namespace std::chrono; | using namespace std::chrono; | ||||
for (size_t i = 0; i < 10; ++i) | for (size_t i = 0; i < 10; ++i) | ||||
{ | { | ||||
co_await resumf_guard_lock(g_lock); | |||||
auto _locker = co_await g_lock.lock(); | |||||
g_queue.push_back(i); | g_queue.push_back(i); | ||||
std::cout << i << " on " << idx << std::endl; | |||||
co_await sleep_for(500ms); | co_await sleep_for(500ms); | ||||
} | } | ||||
void resumable_main_mutex() | void resumable_main_mutex() | ||||
{ | { | ||||
go test_mutex_push(); | |||||
go test_mutex_push(0); | |||||
go test_mutex_pop(1); | go test_mutex_pop(1); | ||||
this_scheduler()->run_until_notask(); | this_scheduler()->run_until_notask(); |
//resumable_main_event(); | //resumable_main_event(); | ||||
//resumable_main_event_timeout(); | //resumable_main_event_timeout(); | ||||
//resumable_main_sleep(); | //resumable_main_sleep(); | ||||
//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])); |
<ClCompile Include="..\benchmark\benchmark_channel_passing_next.cpp" /> | <ClCompile Include="..\benchmark\benchmark_channel_passing_next.cpp" /> | ||||
<ClCompile Include="..\librf\src\event_v1.cpp" /> | <ClCompile Include="..\librf\src\event_v1.cpp" /> | ||||
<ClCompile Include="..\librf\src\event_v2.cpp" /> | <ClCompile Include="..\librf\src\event_v2.cpp" /> | ||||
<ClCompile Include="..\librf\src\mutex.cpp" /> | |||||
<ClCompile Include="..\librf\src\mutex_v1.cpp" /> | |||||
<ClCompile Include="..\librf\src\mutex_v2.cpp" /> | |||||
<ClCompile Include="..\librf\src\rf_task.cpp" /> | <ClCompile Include="..\librf\src\rf_task.cpp" /> | ||||
<ClCompile Include="..\librf\src\scheduler.cpp" /> | <ClCompile Include="..\librf\src\scheduler.cpp" /> | ||||
<ClCompile Include="..\librf\src\sleep.cpp" /> | <ClCompile Include="..\librf\src\sleep.cpp" /> | ||||
<ClInclude Include="..\librf\src\future.h" /> | <ClInclude Include="..\librf\src\future.h" /> | ||||
<ClInclude Include="..\librf\src\generator.h" /> | <ClInclude Include="..\librf\src\generator.h" /> | ||||
<ClInclude Include="..\librf\src\intrusive_link_queue.h" /> | <ClInclude Include="..\librf\src\intrusive_link_queue.h" /> | ||||
<ClInclude Include="..\librf\src\mutex_v1.h" /> | |||||
<ClInclude Include="..\librf\src\mutex_v2.h" /> | |||||
<ClInclude Include="..\librf\src\promise.h" /> | <ClInclude Include="..\librf\src\promise.h" /> | ||||
<ClInclude Include="..\librf\src\mutex.h" /> | <ClInclude Include="..\librf\src\mutex.h" /> | ||||
<ClInclude Include="..\librf\src\rf_task.h" /> | <ClInclude Include="..\librf\src\rf_task.h" /> | ||||
<None Include="..\librf\src\event_v2.inl" /> | <None Include="..\librf\src\event_v2.inl" /> | ||||
<None Include="..\librf\src\exception.inl" /> | <None Include="..\librf\src\exception.inl" /> | ||||
<None Include="..\librf\src\macro_def.inl" /> | <None Include="..\librf\src\macro_def.inl" /> | ||||
<None Include="..\librf\src\mutex_v2.inl" /> | |||||
<None Include="..\librf\src\promise.inl" /> | <None Include="..\librf\src\promise.inl" /> | ||||
<None Include="..\librf\src\state.inl" /> | <None Include="..\librf\src\state.inl" /> | ||||
<None Include="..\librf\src\type_concept.inl" /> | <None Include="..\librf\src\type_concept.inl" /> |
<ClCompile Include="librf.cpp"> | <ClCompile Include="librf.cpp"> | ||||
<Filter>Source Files</Filter> | <Filter>Source Files</Filter> | ||||
</ClCompile> | </ClCompile> | ||||
<ClCompile Include="..\librf\src\mutex.cpp"> | |||||
<Filter>librf\src</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\librf\src\rf_task.cpp"> | <ClCompile Include="..\librf\src\rf_task.cpp"> | ||||
<Filter>librf\src</Filter> | <Filter>librf\src</Filter> | ||||
</ClCompile> | </ClCompile> | ||||
<ClCompile Include="..\librf\src\when_v2.cpp"> | <ClCompile Include="..\librf\src\when_v2.cpp"> | ||||
<Filter>librf\src</Filter> | <Filter>librf\src</Filter> | ||||
</ClCompile> | </ClCompile> | ||||
<ClCompile Include="..\librf\src\mutex_v1.cpp"> | |||||
<Filter>librf\src</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\librf\src\mutex_v2.cpp"> | |||||
<Filter>librf\src</Filter> | |||||
</ClCompile> | |||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<ClInclude Include="..\librf\librf.h"> | <ClInclude Include="..\librf\librf.h"> | ||||
<ClInclude Include="..\librf\src\when_v2.h"> | <ClInclude Include="..\librf\src\when_v2.h"> | ||||
<Filter>librf\src</Filter> | <Filter>librf\src</Filter> | ||||
</ClInclude> | </ClInclude> | ||||
<ClInclude Include="..\librf\src\mutex_v1.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\mutex_v2.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<None Include="..\librf\src\asio_task_1.12.0.inl"> | <None Include="..\librf\src\asio_task_1.12.0.inl"> | ||||
<None Include="..\librf\src\type_concept.inl"> | <None Include="..\librf\src\type_concept.inl"> | ||||
<Filter>librf\src</Filter> | <Filter>librf\src</Filter> | ||||
</None> | </None> | ||||
<None Include="..\librf\src\mutex_v2.inl"> | |||||
<Filter>librf\src</Filter> | |||||
</None> | |||||
</ItemGroup> | </ItemGroup> | ||||
</Project> | </Project> |