mirror of
https://github.com/tearshark/librf.git
synced 2024-10-01 15:57:07 +08:00
实现mutex第二版
This commit is contained in:
parent
ca0177e3bb
commit
946656e34e
@ -1,6 +1,6 @@
|
|||||||
#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
|
||||||
|
@ -10,6 +10,7 @@ RESUMEF_NS
|
|||||||
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__
|
||||||
};
|
};
|
||||||
|
@ -1,89 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
RESUMEF_NS
|
#include "mutex_v1.h"
|
||||||
{
|
#include "mutex_v2.h"
|
||||||
namespace detail
|
#include "mutex_v2.inl"
|
||||||
{
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
@ -1,124 +1,128 @@
|
|||||||
#include "../librf.h"
|
#include "../librf.h"
|
||||||
|
|
||||||
RESUMEF_NS
|
RESUMEF_NS
|
||||||
{
|
{
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
mutex_impl::mutex_impl()
|
mutex_impl::mutex_impl()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void mutex_impl::unlock()
|
void mutex_impl::unlock()
|
||||||
{
|
{
|
||||||
scoped_lock<lock_type> lock_(this->_lock);
|
scoped_lock<lock_type> lock_(this->_lock);
|
||||||
|
|
||||||
if (_owner != nullptr)
|
if (_owner != nullptr)
|
||||||
{
|
{
|
||||||
for (auto iter = _awakes.begin(); iter != _awakes.end(); )
|
for (auto iter = _awakes.begin(); iter != _awakes.end(); )
|
||||||
{
|
{
|
||||||
auto awaker = *iter;
|
auto awaker = *iter;
|
||||||
iter = _awakes.erase(iter);
|
iter = _awakes.erase(iter);
|
||||||
|
|
||||||
if (awaker->awake(this, 1))
|
if (awaker->awake(this, 1))
|
||||||
{
|
{
|
||||||
_owner = awaker;
|
_owner = awaker;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (_awakes.size() == 0)
|
if (_awakes.size() == 0)
|
||||||
{
|
{
|
||||||
_owner = nullptr;
|
_owner = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mutex_impl::lock_(const mutex_awaker_ptr & awaker)
|
bool mutex_impl::lock_(const mutex_awaker_ptr& awaker)
|
||||||
{
|
{
|
||||||
assert(awaker);
|
assert(awaker);
|
||||||
|
|
||||||
scoped_lock<lock_type> lock_(this->_lock);
|
scoped_lock<lock_type> lock_(this->_lock);
|
||||||
|
|
||||||
if (_owner == nullptr)
|
if (_owner == nullptr)
|
||||||
{
|
{
|
||||||
_owner = awaker;
|
_owner = awaker;
|
||||||
awaker->awake(this, 1);
|
awaker->awake(this, 1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_awakes.push_back(awaker);
|
_awakes.push_back(awaker);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mutex_impl::try_lock_(const mutex_awaker_ptr & awaker)
|
bool mutex_impl::try_lock_(const mutex_awaker_ptr& awaker)
|
||||||
{
|
{
|
||||||
assert(awaker);
|
assert(awaker);
|
||||||
|
|
||||||
scoped_lock<lock_type> lock_(this->_lock);
|
scoped_lock<lock_type> lock_(this->_lock);
|
||||||
|
|
||||||
if (_owner == nullptr)
|
if (_owner == nullptr)
|
||||||
{
|
{
|
||||||
_owner = awaker;
|
_owner = awaker;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_t::mutex_t()
|
namespace mutex_v1
|
||||||
: _locker(std::make_shared<detail::mutex_impl>())
|
{
|
||||||
{
|
|
||||||
}
|
mutex_t::mutex_t()
|
||||||
|
: _locker(std::make_shared<detail::mutex_impl>())
|
||||||
future_t<bool> mutex_t::lock() const
|
{
|
||||||
{
|
}
|
||||||
awaitable_t<bool> awaitable;
|
|
||||||
|
future_t<bool> mutex_t::lock() const
|
||||||
auto awaker = std::make_shared<detail::mutex_awaker>(
|
{
|
||||||
[st = awaitable._state](detail::mutex_impl * e) -> bool
|
awaitable_t<bool> awaitable;
|
||||||
{
|
|
||||||
st->set_value(e ? true : false);
|
auto awaker = std::make_shared<detail::mutex_awaker>(
|
||||||
return true;
|
[st = awaitable._state](detail::mutex_impl* e) -> bool
|
||||||
});
|
{
|
||||||
_locker->lock_(awaker);
|
st->set_value(e ? true : false);
|
||||||
|
return true;
|
||||||
return awaitable.get_future();
|
});
|
||||||
}
|
_locker->lock_(awaker);
|
||||||
|
|
||||||
bool mutex_t::try_lock() const
|
return awaitable.get_future();
|
||||||
{
|
}
|
||||||
auto dummy_awaker = std::make_shared<detail::mutex_awaker>(
|
|
||||||
[](detail::mutex_impl * ) -> bool
|
bool mutex_t::try_lock() const
|
||||||
{
|
{
|
||||||
return true;
|
auto dummy_awaker = std::make_shared<detail::mutex_awaker>(
|
||||||
});
|
[](detail::mutex_impl*) -> bool
|
||||||
return _locker->try_lock_(dummy_awaker);
|
{
|
||||||
}
|
return true;
|
||||||
|
});
|
||||||
future_t<bool> mutex_t::try_lock_until_(const clock_type::time_point & tp) const
|
return _locker->try_lock_(dummy_awaker);
|
||||||
{
|
}
|
||||||
awaitable_t<bool> awaitable;
|
|
||||||
|
future_t<bool> mutex_t::try_lock_until_(const clock_type::time_point& tp) const
|
||||||
auto awaker = std::make_shared<detail::mutex_awaker>(
|
{
|
||||||
[st = awaitable._state](detail::mutex_impl * e) -> bool
|
awaitable_t<bool> awaitable;
|
||||||
{
|
|
||||||
st->set_value(e ? true : false);
|
auto awaker = std::make_shared<detail::mutex_awaker>(
|
||||||
return true;
|
[st = awaitable._state](detail::mutex_impl* e) -> bool
|
||||||
});
|
{
|
||||||
_locker->lock_(awaker);
|
st->set_value(e ? true : false);
|
||||||
|
return true;
|
||||||
(void)this_scheduler()->timer()->add(tp,
|
});
|
||||||
[awaker](bool )
|
_locker->lock_(awaker);
|
||||||
{
|
|
||||||
awaker->awake(nullptr, 1);
|
(void)this_scheduler()->timer()->add(tp,
|
||||||
});
|
[awaker](bool)
|
||||||
|
{
|
||||||
return awaitable.get_future();
|
awaker->awake(nullptr, 1);
|
||||||
}
|
});
|
||||||
}
|
|
||||||
|
return awaitable.get_future();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
92
librf/src/mutex_v1.h
Normal file
92
librf/src/mutex_v1.h
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
127
librf/src/mutex_v2.cpp
Normal file
127
librf/src/mutex_v2.cpp
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
#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
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
40
librf/src/mutex_v2.h
Normal file
40
librf/src/mutex_v2.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
203
librf/src/mutex_v2.inl
Normal file
203
librf/src/mutex_v2.inl
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
#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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,7 @@ RESUMEF_NS
|
|||||||
"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];
|
||||||
|
@ -15,7 +15,7 @@ RESUMEF_NS
|
|||||||
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
|
||||||
|
@ -10,6 +10,11 @@ RESUMEF_NS
|
|||||||
{
|
{
|
||||||
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()
|
||||||
{
|
{
|
||||||
@ -88,6 +93,11 @@ RESUMEF_NS
|
|||||||
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);
|
||||||
|
@ -33,6 +33,7 @@ RESUMEF_NS
|
|||||||
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)
|
||||||
{
|
{
|
||||||
@ -42,6 +43,18 @@ RESUMEF_NS
|
|||||||
{
|
{
|
||||||
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
|
||||||
@ -125,7 +138,8 @@ RESUMEF_NS
|
|||||||
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不这么认为。
|
||||||
@ -149,10 +163,6 @@ RESUMEF_NS
|
|||||||
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;
|
||||||
|
@ -19,7 +19,7 @@ future_t<> test_mutex_pop(size_t idx)
|
|||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
@ -32,14 +32,15 @@ future_t<> test_mutex_pop(size_t idx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
@ -47,7 +48,7 @@ future_t<> test_mutex_push()
|
|||||||
|
|
||||||
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();
|
||||||
|
@ -47,7 +47,8 @@ int main(int argc, const char* argv[])
|
|||||||
//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]));
|
||||||
|
@ -183,7 +183,8 @@
|
|||||||
<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" />
|
||||||
@ -233,6 +234,8 @@
|
|||||||
<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" />
|
||||||
@ -260,6 +263,7 @@
|
|||||||
<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" />
|
||||||
|
@ -25,9 +25,6 @@
|
|||||||
<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>
|
||||||
@ -121,6 +118,12 @@
|
|||||||
<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">
|
||||||
@ -228,6 +231,12 @@
|
|||||||
<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">
|
||||||
@ -261,5 +270,8 @@
|
|||||||
<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>
|
Loading…
Reference in New Issue
Block a user