[js][utility] add AsyncLock

This commit is contained in:
方而静 2024-02-10 21:11:20 +08:00
parent 18e8b4f44f
commit 27a4be731d
Signed by: szTom
GPG Key ID: 072D999D60C6473C
2 changed files with 83 additions and 0 deletions

View File

@ -0,0 +1,82 @@
import { Queue } from './queue.mjs';
import { Queue } from './queue.mjs';
/**
* Represents an asynchronous lock for managing access to a shared resource.
* @class
*/
export class AsyncLock {
/**
* Creates an instance of AsyncLock.
* @constructor
*/
constructor() {
/**
* A queue to store pending requests for acquiring the lock.
* @type {Queue}
* @private
*/
this.pending_queue = new Queue();
/**
* The current state of the lock.
* @type {boolean}
* @private
*/
this.state = false;
/**
* The ID associated with the current lock holder.
* @type {number}
* @private
*/
this.lock_id = 0;
}
/**
* Checks the current state of the lock.
* @returns {boolean} True if the lock is acquired; otherwise, false.
*/
query() {
return this.state;
}
/**
* Acquires the lock asynchronously.
* @returns {Promise<number>} A promise that resolves with the unique ID associated with the acquired lock.
*/
acquire() {
if (!this.state) {
this.state = true;
this.lock_id += 1;
return Promise.resolve(this.lock_id);
}
return new Promise((resolve, _reject) => this.pending_queue.push(resolve));
}
/**
* Releases the lock with the specified ID.
* @param {number} lock_id The ID of the lock to release.
*/
release(lock_id) {
if (!this.state || lock_id !== this.lock_id) { return; }
if (this.pending_queue.empty()) {
this.state = false;
return;
}
let resolve = this.pending_queue.front();
this.pending_queue.popFront();
this.lock_id += 1;
resolve(this.lock_id);
}
/**
* Releases the lock forcefully even you are not the owner.
* BE CAREFUL WHAT YOU WISH FOR!!
*/
forceRelease() {
this.release(this.lock_id);
}
};

View File

@ -1,2 +1,3 @@
export { areArrayBuffersEqual } from './buffer.mjs';
export { Queue, QueueEmptyError } from './queue.mjs';
export { AsyncLock } from './async-lock.mjs';