proxygen
folly::coro::Mutex Class Reference

#include <Mutex.h>

Classes

class  LockOperation
 
class  ScopedLockOperation
 

Public Member Functions

 Mutex () noexcept
 Construct a new async mutex that is initially unlocked. More...
 
 Mutex (const Mutex &)=delete
 
 Mutex (Mutex &&)=delete
 
Mutexoperator= (const Mutex &)=delete
 
Mutexoperator= (Mutex &&)=delete
 
 ~Mutex ()
 
bool try_lock () noexcept
 
ScopedLockOperation co_scoped_lock () noexcept
 
LockOperation co_lock () noexcept
 
void unlock () noexcept
 

Private Member Functions

void * unlockedState () noexcept
 
bool lockAsyncImpl (LockOperation *awaiter)
 

Private Attributes

std::atomic< void * > state_
 
LockOperationwaiters_
 

Friends

class LockOperation
 

Detailed Description

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 the lock and then perform the unlock() operation on another thread.

This mutex guarantees a FIFO scheduling algorithm - coroutines acquire the lock in the order that they execute the 'co_await mutex.lockAsync()' operation.

Note that you cannot use std::scoped_lock/std::lock_guard to acquire the lock as the lock must be acquired with use of 'co_await' which cannot be used in a constructor.

You can still use the std::scoped_lock/std::lock_guard in conjunction with std::adopt_lock to automatically unlock the mutex when the current scope exits after having locked the mutex using either co_await m.lock_async() or try_lock() .

You can also attempt to acquire the lock using std::unique_lock in conjunction with std::try_to_lock.

For example: folly::coro::Mutex m; folly::Executor& executor;

folly::coro::Task<> asyncScopedLockExample() { std::unique_lock<folly::coro::Mutex> lock{co_await m.co_scoped_lock()}; ... }

folly::coro::Task<> asyncManualLockAndUnlock() { co_await m.co_lock(executor); ... m.unlock(); }

void nonAsyncTryLock() { if (m.try_lock()) { // Once the lock is acquired you can pass ownership of the lock to // a std::lock_guard object. std::lock_guard<folly::coro::Mutex> lock{m, std::adopt_lock}; ... } }

void nonAsyncScopedTryLock() { std::unique_lock<folly::coro::Mutex> lock{m, std::try_to_lock}; if (lock) { ... } }

Definition at line 84 of file Mutex.h.

Constructor & Destructor Documentation

folly::coro::Mutex::Mutex ( )
inlinenoexcept

Construct a new async mutex that is initially unlocked.

Definition at line 90 of file Mutex.h.

References operator=(), and ~Mutex().

90 : state_(unlockedState()), waiters_(nullptr) {}
std::atomic< void * > state_
Definition: Mutex.h:210
LockOperation * waiters_
Definition: Mutex.h:214
void * unlockedState() noexcept
Definition: Mutex.h:192
folly::coro::Mutex::Mutex ( const Mutex )
delete
folly::coro::Mutex::Mutex ( Mutex &&  )
delete
folly::coro::Mutex::~Mutex ( )

Referenced by Mutex().

Member Function Documentation

Mutex::LockOperation folly::coro::Mutex::co_lock ( )
inlinenoexcept

Lock the mutex asynchronously.

You must co_await the return value to wait until the lock is acquired.

Chain a call to .via() to specify the executor to resume on when the lock is eventually acquired in the case that the lock could not be acquired synchronously. The awaiting coroutine will continue without suspending if the lock could be acquired synchronously.

Once the 'co_await m.lockAsync()' operation completes, the awaiting coroutine is responsible for ensuring that .unlock() is called to release the lock.

Consider using scopedLockAsync() instead to obtain a std::scoped_lock that handles releasing the lock at the end of the scope.

Definition at line 221 of file Mutex.h.

Referenced by try_lock().

221  {
222  return LockOperation{*this};
223 }
friend class LockOperation
Definition: Mutex.h:189
Mutex::ScopedLockOperation folly::coro::Mutex::co_scoped_lock ( )
inlinenoexcept

Lock the mutex asynchronously, returning an RAII object that will release the lock at the end of the scope.

You must co_await the return value to wait until the lock is acquired.

Chain a call to .via() to specify the executor to resume on when the lock is eventually acquired in the case that the lock could not be acquired synchronously. The awaiting coroutine will continue without suspending if the lock could be acquired synchronously.

If you do not specify an executor by calling .via() then the inline executor is used and the awaiting coroutine is resumed inline inside the call to .unlock() by the previous lock holder.

Definition at line 217 of file Mutex.h.

Referenced by try_lock().

217  {
218  return ScopedLockOperation{*this};
219 }
bool folly::coro::Mutex::lockAsyncImpl ( LockOperation awaiter)
private
Mutex& folly::coro::Mutex::operator= ( const Mutex )
delete

Referenced by Mutex().

Mutex& folly::coro::Mutex::operator= ( Mutex &&  )
delete
bool folly::coro::Mutex::try_lock ( )
inlinenoexcept

Try to lock the mutex synchronously.

Returns true if the lock was able to be acquired synchronously, false if the lock could not be acquired because it was already locked.

If this method returns true then the caller is responsible for ensuring that unlock() is called to release the lock.

Definition at line 106 of file Mutex.h.

References co_lock(), co_scoped_lock(), folly::pushmi::__adl::noexcept(), state_, unlock(), and unlockedState().

Referenced by folly::coro::Mutex::LockOperation::await_ready().

106  {
107  void* oldValue = unlockedState();
108  return state_.compare_exchange_strong(
109  oldValue,
110  nullptr,
111  std::memory_order_acquire,
112  std::memory_order_relaxed);
113  }
std::atomic< void * > state_
Definition: Mutex.h:210
void * unlockedState() noexcept
Definition: Mutex.h:192
void folly::coro::Mutex::unlock ( )
noexcept

Unlock the mutex.

If there are other coroutines waiting to lock the mutex then this will schedule the resumption of the next coroutine in the queue.

Referenced by try_lock().

void* folly::coro::Mutex::unlockedState ( )
inlineprivatenoexcept

Definition at line 192 of file Mutex.h.

References lockAsyncImpl().

Referenced by try_lock().

192  {
193  return this;
194  }

Friends And Related Function Documentation

friend class LockOperation
friend

Definition at line 189 of file Mutex.h.

Member Data Documentation

std::atomic<void*> folly::coro::Mutex::state_
private

Definition at line 210 of file Mutex.h.

Referenced by try_lock().

LockOperation* folly::coro::Mutex::waiters_
private

Definition at line 214 of file Mutex.h.


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