CeresEngine 0.2.0
A game development framework
Loading...
Searching...
No Matches
CeresEngine::TAsyncMutex< ExecutorType > Class Template Reference

A mutex that can be locked asynchronously using 'co_await'. More...

#include <CeresEngine/Foundation/Threading/AsyncMutex.hpp>

Classes

class  Lock
 An object that holds onto a mutex lock for its lifetime and ensures that the mutex is unlocked when it is destructed. More...
 
class  LockOperation
 
class  ScopedLockOperation
 

Public Member Functions

 TAsyncMutex () noexcept=default
 Construct to a mutex that is not currently locked.
 
 TAsyncMutex (ExecutorType &&executor) noexcept
 
 ~TAsyncMutex () noexcept
 Destroys the mutex.
 
bool tryLock () noexcept
 Attempt to acquire a lock on the mutex without blocking.
 
bool try_lock () noexcept
 Attempt to acquire a lock on the mutex without blocking.
 
LockOperation lock () noexcept
 Acquire a lock on the mutex asynchronously.
 
ScopedLockOperation scopedLock () noexcept
 Acquire a lock on the mutex asynchronously, returning an object that will call unlock() automatically when it goes out of scope.
 
void unlock ()
 Unlock the mutex.
 

Private Attributes

ExecutorType mExecutor
 This executor is for resuming multiple shared waiters.
 
Atomic< std::uintptr_t > mState = kNotLocked
 This field provides synchronisation for the mutex.
 
LockOperationmWaiters = nullptr
 Linked list of async lock operations that are waiting to acquire the mutex.
 

Static Private Attributes

static constexpr std::uintptr_t kNotLocked = 1
 
static constexpr std::uintptr_t kLockedNoWaiters = 0
 

Friends

class LockOperation
 

Detailed Description

template<typename ExecutorType = InlineExecutor>
class CeresEngine::TAsyncMutex< ExecutorType >

A mutex that can be locked asynchronously using 'co_await'.

Ownership of the mutex is not tied to any particular thread. This allows the coroutine owning the lock to transition from one thread to another while holding a lock.

Implementation is lock-free, using only std::atomic values for synchronisation. Awaiting coroutines are suspended without blocking the current thread if the lock could not be acquired synchronously.

Constructor & Destructor Documentation

◆ TAsyncMutex() [1/2]

template<typename ExecutorType = InlineExecutor>
CeresEngine::TAsyncMutex< ExecutorType >::TAsyncMutex ( )
defaultnoexcept

Construct to a mutex that is not currently locked.

◆ TAsyncMutex() [2/2]

template<typename ExecutorType = InlineExecutor>
CeresEngine::TAsyncMutex< ExecutorType >::TAsyncMutex ( ExecutorType &&  executor)
inlineexplicitnoexcept
Parameters
executorThe executor for when multiple waiters can be woken up at the same time, each shared waiter will be scheduled to immediately run on this executor in parallel.

◆ ~TAsyncMutex()

template<typename ExecutorType = InlineExecutor>
CeresEngine::TAsyncMutex< ExecutorType >::~TAsyncMutex ( )
inlinenoexcept

Destroys the mutex.

Behaviour is undefined if there are any outstanding coroutines still waiting to acquire the lock.

Member Function Documentation

◆ lock()

template<typename ExecutorType = InlineExecutor>
LockOperation CeresEngine::TAsyncMutex< ExecutorType >::lock ( )
inlinenoexcept

Acquire a lock on the mutex asynchronously.

If the lock could not be acquired synchronously then the awaiting coroutine will be suspended and later resumed when the lock becomes available. If suspended, the coroutine will be resumed inside the call to unlock() from the previous lock owner.

Returns
An operation object that must be 'co_await'ed to wait until the lock is acquired. The result of the 'co_await m.lock()' expression has type 'void'.

◆ scopedLock()

template<typename ExecutorType = InlineExecutor>
ScopedLockOperation CeresEngine::TAsyncMutex< ExecutorType >::scopedLock ( )
inlinenoexcept

Acquire a lock on the mutex asynchronously, returning an object that will call unlock() automatically when it goes out of scope.

If the lock could not be acquired synchronously then the awaiting coroutine will be suspended and later resumed when the lock becomes available. If suspended, the coroutine will be resumed inside the call to unlock() from the previous lock owner.

Returns
An operation object that must be 'co_await'ed to wait until the lock is acquired. The result of the 'co_await m.lock()' expression returns an 'AsyncMutexLock' object that will call this->mutex() when it destructs.

◆ try_lock()

template<typename ExecutorType = InlineExecutor>
bool CeresEngine::TAsyncMutex< ExecutorType >::try_lock ( )
inlinenoexcept

Attempt to acquire a lock on the mutex without blocking.

Returns
true if the lock was acquired, false if the mutex was already locked. The caller is responsible for ensuring unlock() is called on the mutex to release the lock if the lock was acquired by this call.

◆ tryLock()

template<typename ExecutorType = InlineExecutor>
bool CeresEngine::TAsyncMutex< ExecutorType >::tryLock ( )
inlinenoexcept

Attempt to acquire a lock on the mutex without blocking.

Returns
true if the lock was acquired, false if the mutex was already locked. The caller is responsible for ensuring unlock() is called on the mutex to release the lock if the lock was acquired by this call.

◆ unlock()

template<typename ExecutorType = InlineExecutor>
void CeresEngine::TAsyncMutex< ExecutorType >::unlock ( )
inline

Unlock the mutex.

Must only be called by the current lock-holder.

If there are lock operations waiting to acquire the mutex then the next lock operation in the queue will be resumed inside this call.

Friends And Related Symbol Documentation

◆ LockOperation

template<typename ExecutorType = InlineExecutor>
friend class LockOperation
friend

Member Data Documentation

◆ kLockedNoWaiters

template<typename ExecutorType = InlineExecutor>
constexpr std::uintptr_t CeresEngine::TAsyncMutex< ExecutorType >::kLockedNoWaiters = 0
staticconstexprprivate

◆ kNotLocked

template<typename ExecutorType = InlineExecutor>
constexpr std::uintptr_t CeresEngine::TAsyncMutex< ExecutorType >::kNotLocked = 1
staticconstexprprivate

◆ mExecutor

template<typename ExecutorType = InlineExecutor>
ExecutorType CeresEngine::TAsyncMutex< ExecutorType >::mExecutor
private

This executor is for resuming multiple shared waiters.

◆ mState

template<typename ExecutorType = InlineExecutor>
Atomic<std::uintptr_t> CeresEngine::TAsyncMutex< ExecutorType >::mState = kNotLocked
private

This field provides synchronisation for the mutex.

It can have three kinds of values:

  • kNotLocked
  • kLockedNoWaiters
  • a pointer to the head of a singly linked list of recently queued LockOperation objects. This list is in most-recently-queued order as new items are pushed onto the front of the list.

◆ mWaiters

template<typename ExecutorType = InlineExecutor>
LockOperation* CeresEngine::TAsyncMutex< ExecutorType >::mWaiters = nullptr
private

Linked list of async lock operations that are waiting to acquire the mutex.

These operations will acquire the lock in the order they appear in this list.


The documentation for this class was generated from the following file: