/** * This class implements a simple mutex using a semaphore. */ export class SimpleMutex implements MutexInterface { /** * This queue is an array of promise resolve functions. * Calling them signals the corresponding consumer that the lock is now free. * The resolve functions resolve with the release function. */ private queue: Array<(release: Mutex.ReleaseFunction) => void> = []; /** * This variable is the semaphore, true if locked, false if not. */ private locked: boolean = false; public acquire(): Promise { return new Promise((resolve) => { this.queue.push(resolve); this.dispatch(); }); } public release(): void { this.locked = false; this.dispatch(); } public reset(): void { this.queue = []; this.locked = false; } public isLocked(): boolean { return this.locked; } /** * This function locks the mutex and calls the next resolve function from the start of the queue. * The resolve function is called with a release function as parameter which unlocks the mutex and calls the function again */ private dispatch(): void { if (this.locked) { return; } const nextResolve = this.queue.shift(); if (!nextResolve) { return; } // lock the resource this.locked = true; // this is the function which gets called by the consumer to release the lock // it also dispatches the next consumer const releaseFunction = (): void => { this.release(); }; // lock the resource and resolve the promise so the consumer can do its thing nextResolve(releaseFunction); } }