Mutex - API
A mutual exclusion primitive useful for protecting shared data.
Installation
- npm
- yarn
- pnpm
npm is the default package manager for Node.js, and to where tscommon is published.
Your project is using npm if it has a
Run the following command in your terminal:
Your project is using npm if it has a
package-lock.json
file in its root folder.Run the following command in your terminal:
terminal
npm install @tscommon/mutex
Usage
Automatic Lock
- With a lock
- Without a lock
main.ts
import assert from 'assert/strict';
import { setTimeout } from 'timers/promises';
import { Mutex } from '@tscommon/mutex';
const mutex = new Mutex(0);
async function increment(check: number): Promise<void> {
// It is important to use the `using` statement to acquire the lock.
await using lock = mutex.lock();
// We use the `await` keyword to wait for the lock to be acquired.
const counter = await lock;
await setTimeout(Math.random() * 1000);
assert(counter.value === check);
counter.value++;
} // The lock is automatically released when the `using` block ends.
async function main(): Promise<void> {
increment(0);
increment(1);
increment(2);
}
main();
main.ts
import assert from 'assert/strict';
import { setTimeout } from 'timers/promises';
let counter = 0;
async function increment(check: number): Promise<void> {
await setTimeout(Math.random() * 1000);
/**
* Here we are not using a mutex to protect the counter.
* This means that the counter is not protected from concurrent access.
* This can lead to an assertion error.
*/
assert(counter === check);
counter++;
}
async function main(): Promise<void> {
increment(0);
increment(1);
increment(2);
}
main();
Try Lock
main.ts
import assert from 'assert/strict';
import { setTimeout } from 'timers/promises';
import { Mutex } from '@tscommon/mutex';
const mutex = new Mutex(0);
async function increment(check: number): Promise<void> {
// It is important to use the `using` statement to acquire the lock.
await using lock = mutex.tryLock();
const counter = await lock;
if (counter) {
// We have acquired the lock.
await setTimeout(Math.random() * 1000);
assert(counter.value === check);
counter.value++;
} else {
// We have not acquired the lock.
}
} // The lock is automatically released when the `using` block ends.
async function main(): Promise<void> {
increment(0);
increment(1);
increment(2);
}
main();
Manual Lock
main.ts
import assert from 'assert/strict';
import { setTimeout } from 'timers/promises';
import { Mutex } from '@tscommon/mutex';
const mutex = new Mutex(0);
async function increment(check: number): Promise<void> {
const lock = mutex.lock();
try {
const counter = await lock;
await setTimeout(Math.random() * 1000);
assert(counter.value === check);
counter.value++;
} finally {
// It is important to release the lock in a `finally` block.
lock.release();
}
}
async function main(): Promise<void> {
increment(0);
increment(1);
increment(2);
}
main();