It's a bit of an edge case, but I couldn't find anything in the documentation that explicitly forbids this behavior.
The use case involves a wrapper around Mutex to manage parent/child locks on resource trees: when a child is locked, any attempt to lock its parent must wait until the child lock is released and viceversa.
In this implementation, it's possible for two or more lock requests to target the same parent/child tree, in which case the existing Mutex instance will be reused.
This leads to the issue:
- The first request acquires the lock.
- The second request ends up both waiting for the current lock to release (
waitForUnlock()) and trying to acquire the lock (acquire()).
As a result it seems the second request deadlocks, since it's simultaneously waiting for the lock to release and trying to acquire it, causing the program to hang.
import { Mutex } from 'async-mutex';
const mtx = new Mutex();
const release = await mtx.acquire();
setTimeout(() => {
release();
}, 1000);
await Promise.all([
mtx.acquire(),
mtx.waitForUnlock(),
]);
// will never reach here
console.log('done');
mtx.release()
It's a bit of an edge case, but I couldn't find anything in the documentation that explicitly forbids this behavior.
The use case involves a wrapper around
Mutexto manage parent/child locks on resource trees: when a child is locked, any attempt to lock its parent must wait until the child lock is released and viceversa.In this implementation, it's possible for two or more lock requests to target the same parent/child tree, in which case the existing
Mutexinstance will be reused.This leads to the issue:
waitForUnlock()) and trying to acquire the lock (acquire()).As a result it seems the second request deadlocks, since it's simultaneously waiting for the lock to release and trying to acquire it, causing the program to hang.