introduce async LockGuard

This commit is contained in:
lganzzzo 2019-06-15 17:26:47 +03:00
parent 2caf7b99b7
commit 892b2b9633
2 changed files with 163 additions and 0 deletions

View File

@ -26,6 +26,9 @@
namespace oatpp { namespace async {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Lock
Lock::Lock()
: m_counter(0)
{
@ -71,4 +74,96 @@ bool Lock::try_lock() {
return result;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// LockGuard
LockGuard::LockGuard()
: m_ownsLock(false)
, m_lock(nullptr)
{}
LockGuard::LockGuard(Lock* lock)
: m_ownsLock(false)
, m_lock(lock)
{}
LockGuard::~LockGuard() {
if(m_ownsLock) {
m_lock->unlock();
}
}
void LockGuard::setLockObject(Lock* lock) {
if(m_lock == nullptr) {
m_lock = lock;
} else if(m_lock != lock) {
throw std::runtime_error("[oatpp::async::LockGuard::setLockObject()]: Error. Invalid state. LockGuard is NOT reusable.");
}
}
CoroutineStarter LockGuard::lockAsync() {
class LockCoroutine : public Coroutine<LockCoroutine> {
private:
LockGuard* m_guard;
public:
LockCoroutine(LockGuard* guard)
: m_guard(guard)
{}
Action act() override {
return m_guard->lockAsyncInline(finish());
}
};
return LockCoroutine::start(this);
}
CoroutineStarter LockGuard::lockAsync(Lock* lock) {
setLockObject(lock);
return lockAsync();
}
Action LockGuard::lockAsyncInline(oatpp::async::Action&& nextAction) {
if(!m_ownsLock) {
m_ownsLock = m_lock->try_lock();
if(m_ownsLock) {
return std::forward<Action>(nextAction);
} else {
return m_lock->waitAsync();
}
} else {
throw std::runtime_error("[oatpp::async::LockGuard::lockAsyncInline()]: Error. Invalid state. Double lock attempt.");
}
}
void LockGuard::unlock() {
if(m_lock) {
if(m_ownsLock) {
m_lock->unlock();
} else {
throw std::runtime_error("[oatpp::async::LockGuard::unlock()]: Error. Invalid state. LockGuard is NOT owning the lock.");
}
} else {
throw std::runtime_error("[oatpp::async::LockGuard::unlock()]: Error. Invalid state. Lock object is nullptr.");
}
}
}}

View File

@ -72,6 +72,74 @@ public:
};
/**
* Asynchronous lock guard. <br>
* Should be used as a lock guard in coroutines.
*/
class LockGuard {
public:
/**
* Convenince typedef for &id:oatpp::async::CoroutineStarter;.
*/
typedef oatpp::async::CoroutineStarter CoroutineStarter;
private:
bool m_ownsLock;
Lock* m_lock;
public:
LockGuard(const LockGuard&) = delete;
LockGuard& operator = (const LockGuard&) = delete;
public:
/**
* Default constructor.
*/
LockGuard();
/**
* Default constructor.
*/
LockGuard(Lock* lock);
/**
* Non-virtual destructor. <br>
* Will unlock the Lock if owns lock.
*/
~LockGuard();
/**
* Set lock object.
* @param lock - lock object.
*/
void setLockObject(Lock* lock);
/**
* Lock the lock.
* @return - &id:oatpp::async::Action;.
*/
CoroutineStarter lockAsync();
/**
* Lock and guard the lock. <br>
* Same as `setLockObject(lock) + lockAsync();`.
* @param lock - lock to lock and guard.
* @return - &id:oatpp::async::Action;.
*/
CoroutineStarter lockAsync(Lock* lock);
/**
* Lock the lock. (Async-inline usage. Should be called from a separate method of coroutine).
* @param nextAction - action to take after lock is locked.
* @return - &id:oatpp::async::Action;.
*/
Action lockAsyncInline(oatpp::async::Action&& nextAction);
/**
* Unlock guarded lock.
*/
void unlock();
};
}}
#endif // oatpp_async_Mutex_hpp