constincrement = async () => { awaitmutex.scopedLock(async () => { // only one context can be inside this block at a time, // so the read-modify-write below is never interleaved constcurrent = counter; awaitnewPromise((resolve) =>setTimeout(resolve, 10)); counter = current + 1; }); };
The value returned by the closure is returned to the caller, and exceptions
thrown by the closure are re-thrown to the caller. The lock is released
in both cases.
Fairness
The lock is handed off directly to the context that has been waiting the longest,
so waiters are guaranteed to acquire the lock in the order they called
scopedLock. A context that starts waiting while the lock is being
released cannot barge in front of the contexts already waiting.
Non-reentrant mutex
This allows only one context to enter a block at a time in a FIFO manner.
This mutex is non-reentrant. Trying to lock it again while the same context already owns the lock will cause a dead lock.
While a context id can be used to implement reentrant locks, it is very cumbersome to use. https://github.com/tc39/proposal-async-context will allow for a cleaner implementation.
Example
The value returned by the closure is returned to the caller, and exceptions thrown by the closure are re-thrown to the caller. The lock is released in both cases.
Fairness
The lock is handed off directly to the context that has been waiting the longest, so waiters are guaranteed to acquire the lock in the order they called scopedLock. A context that starts waiting while the lock is being released cannot barge in front of the contexts already waiting.