53 lines
1.5 KiB
TypeScript
53 lines
1.5 KiB
TypeScript
|
/**
|
||
|
* This class implements a simple mutex using a semaphore.
|
||
|
*/
|
||
|
export class SimpleMutex implements IMutex {
|
||
|
/**
|
||
|
* 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<Mutex.ReleaseFunction> {
|
||
|
return new Promise<Mutex.ReleaseFunction>((resolve) => {
|
||
|
this.queue.push(resolve);
|
||
|
this.dispatch();
|
||
|
});
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
this.locked = true;
|
||
|
|
||
|
// this is the function which gets called by the consumer to release the lock
|
||
|
// it also dispatches the next consumer (recursive call)
|
||
|
const releaseFunction = (): void => {
|
||
|
this.locked = false;
|
||
|
this.dispatch();
|
||
|
};
|
||
|
|
||
|
// lock the resource and resolve the promise so the consumer can do its thing
|
||
|
nextResolve(releaseFunction);
|
||
|
}
|
||
|
}
|