63 lines
1.6 KiB
TypeScript
63 lines
1.6 KiB
TypeScript
/**
|
|
* 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<Mutex.ReleaseFunction> {
|
|
return new Promise<Mutex.ReleaseFunction>((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);
|
|
}
|
|
}
|