async-mutex
Advanced tools
Comparing version 0.3.2 to 0.4.0
@@ -29,5 +29,5 @@ import { __awaiter, __generator } from "tslib"; | ||
}; | ||
/** @deprecated Deprecated in 0.3.0, will be removed in 0.4.0. Use runExclusive instead. */ | ||
Mutex.prototype.release = function () { | ||
this._semaphore.release(); | ||
if (this._semaphore.isLocked()) | ||
this._semaphore.release(); | ||
}; | ||
@@ -34,0 +34,0 @@ Mutex.prototype.cancel = function () { |
import { __awaiter, __generator } from "tslib"; | ||
import { E_CANCELED } from './errors'; | ||
var Semaphore = /** @class */ (function () { | ||
function Semaphore(_maxConcurrency, _cancelError) { | ||
function Semaphore(_value, _cancelError) { | ||
if (_cancelError === void 0) { _cancelError = E_CANCELED; } | ||
this._maxConcurrency = _maxConcurrency; | ||
this._value = _value; | ||
this._cancelError = _cancelError; | ||
this._queue = []; | ||
this._waiters = []; | ||
if (_maxConcurrency <= 0) { | ||
throw new Error('semaphore must be initialized to a positive value'); | ||
} | ||
this._value = _maxConcurrency; | ||
this._weightedQueues = []; | ||
this._weightedWaiters = []; | ||
} | ||
Semaphore.prototype.acquire = function () { | ||
Semaphore.prototype.acquire = function (weight) { | ||
var _this = this; | ||
var locked = this.isLocked(); | ||
var ticketPromise = new Promise(function (resolve, reject) { | ||
return _this._queue.push({ resolve: resolve, reject: reject }); | ||
if (weight === void 0) { weight = 1; } | ||
if (weight <= 0) | ||
throw new Error("invalid weight ".concat(weight, ": must be positive")); | ||
return new Promise(function (resolve, reject) { | ||
if (!_this._weightedQueues[weight - 1]) | ||
_this._weightedQueues[weight - 1] = []; | ||
_this._weightedQueues[weight - 1].push({ resolve: resolve, reject: reject }); | ||
_this._dispatch(); | ||
}); | ||
if (!locked) | ||
this._dispatch(); | ||
return ticketPromise; | ||
}; | ||
Semaphore.prototype.runExclusive = function (callback) { | ||
Semaphore.prototype.runExclusive = function (callback, weight) { | ||
if (weight === void 0) { weight = 1; } | ||
return __awaiter(this, void 0, void 0, function () { | ||
@@ -30,3 +29,3 @@ var _a, value, release; | ||
switch (_b.label) { | ||
case 0: return [4 /*yield*/, this.acquire()]; | ||
case 0: return [4 /*yield*/, this.acquire(weight)]; | ||
case 1: | ||
@@ -47,13 +46,12 @@ _a = _b.sent(), value = _a[0], release = _a[1]; | ||
}; | ||
Semaphore.prototype.waitForUnlock = function () { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var waitPromise; | ||
var _this = this; | ||
return __generator(this, function (_a) { | ||
if (!this.isLocked()) { | ||
return [2 /*return*/, Promise.resolve()]; | ||
} | ||
waitPromise = new Promise(function (resolve) { return _this._waiters.push({ resolve: resolve }); }); | ||
return [2 /*return*/, waitPromise]; | ||
}); | ||
Semaphore.prototype.waitForUnlock = function (weight) { | ||
var _this = this; | ||
if (weight === void 0) { weight = 1; } | ||
if (weight <= 0) | ||
throw new Error("invalid weight ".concat(weight, ": must be positive")); | ||
return new Promise(function (resolve) { | ||
if (!_this._weightedWaiters[weight - 1]) | ||
_this._weightedWaiters[weight - 1] = []; | ||
_this._weightedWaiters[weight - 1].push(resolve); | ||
_this._dispatch(); | ||
}); | ||
@@ -64,37 +62,52 @@ }; | ||
}; | ||
/** @deprecated Deprecated in 0.3.0, will be removed in 0.4.0. Use runExclusive instead. */ | ||
Semaphore.prototype.release = function () { | ||
if (this._maxConcurrency > 1) { | ||
throw new Error('this method is unavailable on semaphores with concurrency > 1; use the scoped release returned by acquire instead'); | ||
} | ||
if (this._currentReleaser) { | ||
var releaser = this._currentReleaser; | ||
this._currentReleaser = undefined; | ||
releaser(); | ||
} | ||
Semaphore.prototype.getValue = function () { | ||
return this._value; | ||
}; | ||
Semaphore.prototype.setValue = function (value) { | ||
this._value = value; | ||
this._dispatch(); | ||
}; | ||
Semaphore.prototype.release = function (weight) { | ||
if (weight === void 0) { weight = 1; } | ||
if (weight <= 0) | ||
throw new Error("invalid weight ".concat(weight, ": must be positive")); | ||
this._value += weight; | ||
this._dispatch(); | ||
}; | ||
Semaphore.prototype.cancel = function () { | ||
var _this = this; | ||
this._queue.forEach(function (ticket) { return ticket.reject(_this._cancelError); }); | ||
this._queue = []; | ||
this._weightedQueues.forEach(function (queue) { return queue.forEach(function (entry) { return entry.reject(_this._cancelError); }); }); | ||
this._weightedQueues = []; | ||
}; | ||
Semaphore.prototype._dispatch = function () { | ||
var _a; | ||
for (var weight = this._value; weight > 0; weight--) { | ||
var queueEntry = (_a = this._weightedQueues[weight - 1]) === null || _a === void 0 ? void 0 : _a.shift(); | ||
if (!queueEntry) | ||
continue; | ||
var previousValue = this._value; | ||
var previousWeight = weight; | ||
this._value -= weight; | ||
weight = this._value + 1; | ||
queueEntry.resolve([previousValue, this._newReleaser(previousWeight)]); | ||
} | ||
this._drainUnlockWaiters(); | ||
}; | ||
Semaphore.prototype._newReleaser = function (weight) { | ||
var _this = this; | ||
var nextTicket = this._queue.shift(); | ||
if (!nextTicket) | ||
return; | ||
var released = false; | ||
this._currentReleaser = function () { | ||
if (released) | ||
var called = false; | ||
return function () { | ||
if (called) | ||
return; | ||
released = true; | ||
_this._value++; | ||
_this._resolveWaiters(); | ||
_this._dispatch(); | ||
called = true; | ||
_this.release(weight); | ||
}; | ||
nextTicket.resolve([this._value--, this._currentReleaser]); | ||
}; | ||
Semaphore.prototype._resolveWaiters = function () { | ||
this._waiters.forEach(function (waiter) { return waiter.resolve(); }); | ||
this._waiters = []; | ||
Semaphore.prototype._drainUnlockWaiters = function () { | ||
for (var weight = this._value; weight > 0; weight--) { | ||
if (!this._weightedWaiters[weight - 1]) | ||
continue; | ||
this._weightedWaiters[weight - 1].forEach(function (waiter) { return waiter(); }); | ||
this._weightedWaiters[weight - 1] = []; | ||
} | ||
}; | ||
@@ -101,0 +114,0 @@ return Semaphore; |
import { __awaiter, __generator } from "tslib"; | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
import { E_TIMEOUT } from './errors'; | ||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types | ||
export function withTimeout(sync, timeout, timeoutError) { | ||
@@ -8,3 +8,6 @@ var _this = this; | ||
return { | ||
acquire: function () { | ||
acquire: function (weight) { | ||
if (weight !== undefined && weight <= 0) { | ||
throw new Error("invalid weight ".concat(weight, ": must be positive")); | ||
} | ||
return new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () { | ||
@@ -23,3 +26,3 @@ var isTimeout, handle, ticket, release, e_1; | ||
_a.trys.push([1, 3, , 4]); | ||
return [4 /*yield*/, sync.acquire()]; | ||
return [4 /*yield*/, sync.acquire(weight)]; | ||
case 2: | ||
@@ -48,3 +51,3 @@ ticket = _a.sent(); | ||
}, | ||
runExclusive: function (callback) { | ||
runExclusive: function (callback, weight) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
@@ -59,3 +62,3 @@ var release, ticket; | ||
_a.trys.push([1, , 7, 8]); | ||
return [4 /*yield*/, this.acquire()]; | ||
return [4 /*yield*/, this.acquire(weight)]; | ||
case 2: | ||
@@ -80,5 +83,4 @@ ticket = _a.sent(); | ||
}, | ||
/** @deprecated Deprecated in 0.3.0, will be removed in 0.4.0. Use runExclusive instead. */ | ||
release: function () { | ||
sync.release(); | ||
release: function (weight) { | ||
sync.release(weight); | ||
}, | ||
@@ -88,5 +90,15 @@ cancel: function () { | ||
}, | ||
waitForUnlock: function () { return sync.waitForUnlock(); }, | ||
waitForUnlock: function (weight) { | ||
if (weight !== undefined && weight <= 0) { | ||
throw new Error("invalid weight ".concat(weight, ": must be positive")); | ||
} | ||
return new Promise(function (resolve, reject) { | ||
sync.waitForUnlock(weight).then(resolve); | ||
setTimeout(function () { return reject(timeoutError); }, timeout); | ||
}); | ||
}, | ||
isLocked: function () { return sync.isLocked(); }, | ||
getValue: function () { return sync.getValue(); }, | ||
setValue: function (value) { return sync.setValue(value); }, | ||
}; | ||
} |
@@ -13,2 +13,2 @@ "use strict"; | ||
Object.defineProperty(exports, "tryAcquire", { enumerable: true, get: function () { return tryAcquire_1.tryAcquire; } }); | ||
(0, tslib_1.__exportStar)(require("./errors"), exports); | ||
tslib_1.__exportStar(require("./errors"), exports); |
@@ -8,3 +8,2 @@ import MutexInterface from './MutexInterface'; | ||
waitForUnlock(): Promise<void>; | ||
/** @deprecated Deprecated in 0.3.0, will be removed in 0.4.0. Use runExclusive instead. */ | ||
release(): void; | ||
@@ -11,0 +10,0 @@ cancel(): void; |
@@ -10,5 +10,5 @@ "use strict"; | ||
Mutex.prototype.acquire = function () { | ||
return (0, tslib_1.__awaiter)(this, void 0, void 0, function () { | ||
return tslib_1.__awaiter(this, void 0, void 0, function () { | ||
var _a, releaser; | ||
return (0, tslib_1.__generator)(this, function (_b) { | ||
return tslib_1.__generator(this, function (_b) { | ||
switch (_b.label) { | ||
@@ -32,5 +32,5 @@ case 0: return [4 /*yield*/, this._semaphore.acquire()]; | ||
}; | ||
/** @deprecated Deprecated in 0.3.0, will be removed in 0.4.0. Use runExclusive instead. */ | ||
Mutex.prototype.release = function () { | ||
this._semaphore.release(); | ||
if (this._semaphore.isLocked()) | ||
this._semaphore.release(); | ||
}; | ||
@@ -37,0 +37,0 @@ Mutex.prototype.cancel = function () { |
@@ -6,3 +6,2 @@ interface MutexInterface { | ||
isLocked(): boolean; | ||
/** @deprecated Deprecated in 0.3.0, will be removed in 0.4.0. Use runExclusive instead. */ | ||
release(): void; | ||
@@ -9,0 +8,0 @@ cancel(): void; |
import SemaphoreInterface from './SemaphoreInterface'; | ||
declare class Semaphore implements SemaphoreInterface { | ||
private _maxConcurrency; | ||
private _value; | ||
private _cancelError; | ||
constructor(_maxConcurrency: number, _cancelError?: Error); | ||
acquire(): Promise<[number, SemaphoreInterface.Releaser]>; | ||
runExclusive<T>(callback: SemaphoreInterface.Worker<T>): Promise<T>; | ||
waitForUnlock(): Promise<void>; | ||
constructor(_value: number, _cancelError?: Error); | ||
acquire(weight?: number): Promise<[number, SemaphoreInterface.Releaser]>; | ||
runExclusive<T>(callback: SemaphoreInterface.Worker<T>, weight?: number): Promise<T>; | ||
waitForUnlock(weight?: number): Promise<void>; | ||
isLocked(): boolean; | ||
/** @deprecated Deprecated in 0.3.0, will be removed in 0.4.0. Use runExclusive instead. */ | ||
release(): void; | ||
getValue(): number; | ||
setValue(value: number): void; | ||
release(weight?: number): void; | ||
cancel(): void; | ||
private _dispatch; | ||
private _resolveWaiters; | ||
private _queue; | ||
private _waiters; | ||
private _currentReleaser; | ||
private _value; | ||
private _newReleaser; | ||
private _drainUnlockWaiters; | ||
private _weightedQueues; | ||
private _weightedWaiters; | ||
} | ||
export default Semaphore; |
@@ -6,29 +6,28 @@ "use strict"; | ||
var Semaphore = /** @class */ (function () { | ||
function Semaphore(_maxConcurrency, _cancelError) { | ||
function Semaphore(_value, _cancelError) { | ||
if (_cancelError === void 0) { _cancelError = errors_1.E_CANCELED; } | ||
this._maxConcurrency = _maxConcurrency; | ||
this._value = _value; | ||
this._cancelError = _cancelError; | ||
this._queue = []; | ||
this._waiters = []; | ||
if (_maxConcurrency <= 0) { | ||
throw new Error('semaphore must be initialized to a positive value'); | ||
} | ||
this._value = _maxConcurrency; | ||
this._weightedQueues = []; | ||
this._weightedWaiters = []; | ||
} | ||
Semaphore.prototype.acquire = function () { | ||
Semaphore.prototype.acquire = function (weight) { | ||
var _this = this; | ||
var locked = this.isLocked(); | ||
var ticketPromise = new Promise(function (resolve, reject) { | ||
return _this._queue.push({ resolve: resolve, reject: reject }); | ||
if (weight === void 0) { weight = 1; } | ||
if (weight <= 0) | ||
throw new Error("invalid weight ".concat(weight, ": must be positive")); | ||
return new Promise(function (resolve, reject) { | ||
if (!_this._weightedQueues[weight - 1]) | ||
_this._weightedQueues[weight - 1] = []; | ||
_this._weightedQueues[weight - 1].push({ resolve: resolve, reject: reject }); | ||
_this._dispatch(); | ||
}); | ||
if (!locked) | ||
this._dispatch(); | ||
return ticketPromise; | ||
}; | ||
Semaphore.prototype.runExclusive = function (callback) { | ||
return (0, tslib_1.__awaiter)(this, void 0, void 0, function () { | ||
Semaphore.prototype.runExclusive = function (callback, weight) { | ||
if (weight === void 0) { weight = 1; } | ||
return tslib_1.__awaiter(this, void 0, void 0, function () { | ||
var _a, value, release; | ||
return (0, tslib_1.__generator)(this, function (_b) { | ||
return tslib_1.__generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: return [4 /*yield*/, this.acquire()]; | ||
case 0: return [4 /*yield*/, this.acquire(weight)]; | ||
case 1: | ||
@@ -49,13 +48,12 @@ _a = _b.sent(), value = _a[0], release = _a[1]; | ||
}; | ||
Semaphore.prototype.waitForUnlock = function () { | ||
return (0, tslib_1.__awaiter)(this, void 0, void 0, function () { | ||
var waitPromise; | ||
var _this = this; | ||
return (0, tslib_1.__generator)(this, function (_a) { | ||
if (!this.isLocked()) { | ||
return [2 /*return*/, Promise.resolve()]; | ||
} | ||
waitPromise = new Promise(function (resolve) { return _this._waiters.push({ resolve: resolve }); }); | ||
return [2 /*return*/, waitPromise]; | ||
}); | ||
Semaphore.prototype.waitForUnlock = function (weight) { | ||
var _this = this; | ||
if (weight === void 0) { weight = 1; } | ||
if (weight <= 0) | ||
throw new Error("invalid weight ".concat(weight, ": must be positive")); | ||
return new Promise(function (resolve) { | ||
if (!_this._weightedWaiters[weight - 1]) | ||
_this._weightedWaiters[weight - 1] = []; | ||
_this._weightedWaiters[weight - 1].push(resolve); | ||
_this._dispatch(); | ||
}); | ||
@@ -66,37 +64,52 @@ }; | ||
}; | ||
/** @deprecated Deprecated in 0.3.0, will be removed in 0.4.0. Use runExclusive instead. */ | ||
Semaphore.prototype.release = function () { | ||
if (this._maxConcurrency > 1) { | ||
throw new Error('this method is unavailable on semaphores with concurrency > 1; use the scoped release returned by acquire instead'); | ||
} | ||
if (this._currentReleaser) { | ||
var releaser = this._currentReleaser; | ||
this._currentReleaser = undefined; | ||
releaser(); | ||
} | ||
Semaphore.prototype.getValue = function () { | ||
return this._value; | ||
}; | ||
Semaphore.prototype.setValue = function (value) { | ||
this._value = value; | ||
this._dispatch(); | ||
}; | ||
Semaphore.prototype.release = function (weight) { | ||
if (weight === void 0) { weight = 1; } | ||
if (weight <= 0) | ||
throw new Error("invalid weight ".concat(weight, ": must be positive")); | ||
this._value += weight; | ||
this._dispatch(); | ||
}; | ||
Semaphore.prototype.cancel = function () { | ||
var _this = this; | ||
this._queue.forEach(function (ticket) { return ticket.reject(_this._cancelError); }); | ||
this._queue = []; | ||
this._weightedQueues.forEach(function (queue) { return queue.forEach(function (entry) { return entry.reject(_this._cancelError); }); }); | ||
this._weightedQueues = []; | ||
}; | ||
Semaphore.prototype._dispatch = function () { | ||
var _a; | ||
for (var weight = this._value; weight > 0; weight--) { | ||
var queueEntry = (_a = this._weightedQueues[weight - 1]) === null || _a === void 0 ? void 0 : _a.shift(); | ||
if (!queueEntry) | ||
continue; | ||
var previousValue = this._value; | ||
var previousWeight = weight; | ||
this._value -= weight; | ||
weight = this._value + 1; | ||
queueEntry.resolve([previousValue, this._newReleaser(previousWeight)]); | ||
} | ||
this._drainUnlockWaiters(); | ||
}; | ||
Semaphore.prototype._newReleaser = function (weight) { | ||
var _this = this; | ||
var nextTicket = this._queue.shift(); | ||
if (!nextTicket) | ||
return; | ||
var released = false; | ||
this._currentReleaser = function () { | ||
if (released) | ||
var called = false; | ||
return function () { | ||
if (called) | ||
return; | ||
released = true; | ||
_this._value++; | ||
_this._resolveWaiters(); | ||
_this._dispatch(); | ||
called = true; | ||
_this.release(weight); | ||
}; | ||
nextTicket.resolve([this._value--, this._currentReleaser]); | ||
}; | ||
Semaphore.prototype._resolveWaiters = function () { | ||
this._waiters.forEach(function (waiter) { return waiter.resolve(); }); | ||
this._waiters = []; | ||
Semaphore.prototype._drainUnlockWaiters = function () { | ||
for (var weight = this._value; weight > 0; weight--) { | ||
if (!this._weightedWaiters[weight - 1]) | ||
continue; | ||
this._weightedWaiters[weight - 1].forEach(function (waiter) { return waiter(); }); | ||
this._weightedWaiters[weight - 1] = []; | ||
} | ||
}; | ||
@@ -103,0 +116,0 @@ return Semaphore; |
interface SemaphoreInterface { | ||
acquire(): Promise<[number, SemaphoreInterface.Releaser]>; | ||
runExclusive<T>(callback: SemaphoreInterface.Worker<T>): Promise<T>; | ||
waitForUnlock(): Promise<void>; | ||
acquire(weight?: number): Promise<[number, SemaphoreInterface.Releaser]>; | ||
runExclusive<T>(callback: SemaphoreInterface.Worker<T>, weight?: number): Promise<T>; | ||
waitForUnlock(weight?: number): Promise<void>; | ||
isLocked(): boolean; | ||
/** @deprecated Deprecated in 0.3.0, will be removed in 0.4.0. Use runExclusive instead. */ | ||
release(): void; | ||
getValue(): number; | ||
setValue(value: number): void; | ||
release(weight?: number): void; | ||
cancel(): void; | ||
@@ -9,0 +10,0 @@ } |
@@ -5,4 +5,4 @@ "use strict"; | ||
var tslib_1 = require("tslib"); | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
var errors_1 = require("./errors"); | ||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types | ||
function withTimeout(sync, timeout, timeoutError) { | ||
@@ -12,6 +12,9 @@ var _this = this; | ||
return { | ||
acquire: function () { | ||
return new Promise(function (resolve, reject) { return (0, tslib_1.__awaiter)(_this, void 0, void 0, function () { | ||
acquire: function (weight) { | ||
if (weight !== undefined && weight <= 0) { | ||
throw new Error("invalid weight ".concat(weight, ": must be positive")); | ||
} | ||
return new Promise(function (resolve, reject) { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
var isTimeout, handle, ticket, release, e_1; | ||
return (0, tslib_1.__generator)(this, function (_a) { | ||
return tslib_1.__generator(this, function (_a) { | ||
switch (_a.label) { | ||
@@ -27,3 +30,3 @@ case 0: | ||
_a.trys.push([1, 3, , 4]); | ||
return [4 /*yield*/, sync.acquire()]; | ||
return [4 /*yield*/, sync.acquire(weight)]; | ||
case 2: | ||
@@ -52,6 +55,6 @@ ticket = _a.sent(); | ||
}, | ||
runExclusive: function (callback) { | ||
return (0, tslib_1.__awaiter)(this, void 0, void 0, function () { | ||
runExclusive: function (callback, weight) { | ||
return tslib_1.__awaiter(this, void 0, void 0, function () { | ||
var release, ticket; | ||
return (0, tslib_1.__generator)(this, function (_a) { | ||
return tslib_1.__generator(this, function (_a) { | ||
switch (_a.label) { | ||
@@ -63,3 +66,3 @@ case 0: | ||
_a.trys.push([1, , 7, 8]); | ||
return [4 /*yield*/, this.acquire()]; | ||
return [4 /*yield*/, this.acquire(weight)]; | ||
case 2: | ||
@@ -84,5 +87,4 @@ ticket = _a.sent(); | ||
}, | ||
/** @deprecated Deprecated in 0.3.0, will be removed in 0.4.0. Use runExclusive instead. */ | ||
release: function () { | ||
sync.release(); | ||
release: function (weight) { | ||
sync.release(weight); | ||
}, | ||
@@ -92,6 +94,16 @@ cancel: function () { | ||
}, | ||
waitForUnlock: function () { return sync.waitForUnlock(); }, | ||
waitForUnlock: function (weight) { | ||
if (weight !== undefined && weight <= 0) { | ||
throw new Error("invalid weight ".concat(weight, ": must be positive")); | ||
} | ||
return new Promise(function (resolve, reject) { | ||
sync.waitForUnlock(weight).then(resolve); | ||
setTimeout(function () { return reject(timeoutError); }, timeout); | ||
}); | ||
}, | ||
isLocked: function () { return sync.isLocked(); }, | ||
getValue: function () { return sync.getValue(); }, | ||
setValue: function (value) { return sync.setValue(value); }, | ||
}; | ||
} | ||
exports.withTimeout = withTimeout; |
{ | ||
"name": "async-mutex", | ||
"version": "0.3.2", | ||
"version": "0.4.0", | ||
"description": "A mutex for guarding async workflows", | ||
@@ -57,18 +57,18 @@ "scripts": { | ||
"devDependencies": { | ||
"@sinonjs/fake-timers": "^7.1.2", | ||
"@types/mocha": "^9.0.0", | ||
"@types/node": "^16.7.8", | ||
"@types/sinonjs__fake-timers": "^6.0.3", | ||
"@typescript-eslint/eslint-plugin": "^4.30.0", | ||
"@typescript-eslint/parser": "^4.30.0", | ||
"@sinonjs/fake-timers": "^9.1.2", | ||
"@types/mocha": "^9.1.1", | ||
"@types/node": "^18.7.14", | ||
"@types/sinonjs__fake-timers": "^8.1.2", | ||
"@typescript-eslint/eslint-plugin": "^5.36.1", | ||
"@typescript-eslint/parser": "^5.36.1", | ||
"coveralls": "^3.1.1", | ||
"eslint": "^7.32.0", | ||
"eslint": "^8.23.0", | ||
"import-sort-style-eslint": "^6.0.0", | ||
"mocha": "^9.1.1", | ||
"mocha": "^10.0.0", | ||
"nyc": "^15.1.0", | ||
"prettier": "^2.3.2", | ||
"prettier": "^2.7.1", | ||
"prettier-plugin-import-sort": "^0.0.7", | ||
"rollup": "^2.56.3", | ||
"ts-node": "^10.2.1", | ||
"typescript": "^4.4.2" | ||
"ts-node": "^10.9.1", | ||
"typescript": "^4.8.2" | ||
}, | ||
@@ -87,4 +87,4 @@ "main": "lib/index.js", | ||
"dependencies": { | ||
"tslib": "^2.3.1" | ||
"tslib": "^2.4.0" | ||
} | ||
} |
@@ -42,3 +42,3 @@ [![Build status](https://github.com/DirtyHairy/async-mutex/workflows/Build%20and%20Tests/badge.svg)](https://github.com/DirtyHairy/async-mutex/actions?query=workflow%3A%22Build+and+Tests%22) | ||
A semaphore is a data structure that is initialized to a positive integer value and that | ||
A semaphore is a data structure that is initialized to an arbitrary integer value and that | ||
can be locked multiple times. | ||
@@ -159,3 +159,4 @@ As long as the semaphore value is positive, locking it will return the current value | ||
available. The promise resolves with a function `release` that | ||
must be called once the mutex should be released again. | ||
must be called once the mutex should be released again. The `release` callback | ||
is idempotent. | ||
@@ -166,6 +167,11 @@ **IMPORTANT:** Failure to call `release` will hold the mutex locked and will | ||
`acquire` / `release` should be considered a low level API. In most situations, | ||
`runExclusive` will be a better choice that automatically takes care of releasing | ||
the mutex once a block of code has executed exclusively. | ||
### Unscoped release | ||
As an alternative to calling the `release` callback returned by `acquire`, the mutex | ||
can be released by calling `release` directly on it: | ||
```typescript | ||
mutex.release(); | ||
``` | ||
### Checking whether the mutex is locked | ||
@@ -232,3 +238,3 @@ | ||
This will return a promise that resolve once the mutex can be acquired again. This operation | ||
will not lock the mutex, and there is no gurantee that the mutex will still be available | ||
will not lock the mutex, and there is no guarantee that the mutex will still be available | ||
once a async barrier has been encountered. | ||
@@ -260,4 +266,4 @@ | ||
Creates a new semaphore. `initialValue` is a positive integer that defines the | ||
initial value of the semaphore (aka the maximum number of concurrent consumers). | ||
Creates a new semaphore. `initialValue` is an arbitrary integer that defines the | ||
initial value of the semaphore. | ||
@@ -293,2 +299,6 @@ ### Synchronized code execution | ||
`runExclusive` accepts an optional argument `weight`. Specifying a `weight` will decrement the | ||
semaphore by the specified value, and the callback will only be invoked once the semaphore's | ||
value greater or equal to `weight`. | ||
### Manual locking / releasing | ||
@@ -321,3 +331,3 @@ | ||
function that must be called to release the semaphore once the critical operation | ||
has completed. | ||
has completed. The `release` callback is idempotent. | ||
@@ -328,6 +338,28 @@ **IMPORTANT:** Failure to call `release` will hold the semaphore locked and will | ||
`acquire` / `release` should be considered a low level API. In most situations, | ||
`runExclusive` will be a better choice that automatically takes care of releasing | ||
the mutex once a block of code has executed exclusively. | ||
`runExclusive` accepts an optional argument `weight`. Specifying a `weight` will decrement the | ||
semaphore by the specified value, and the semaphore will only be acquired once the its | ||
value is greater or equal to. | ||
### Unscoped release | ||
As an alternative to calling the `release` callback return by `acquire`, the mutex | ||
can be released by calling `release` directly on it: | ||
```typescript | ||
mutex.release(); | ||
``` | ||
`release` accepts an optional argument `weight` and increments the semaphore accordingly. | ||
**IMPORTANT:** Releasing a previously acquired semaphore with the releaser that was | ||
returned by acquire will automatically increment the semaphore by the correct weight. If | ||
you release by calling the unscoped `release` you have to supply the correct weight | ||
yourself! | ||
### Getting the semaphore value | ||
```typescript | ||
semaphore.getValue() | ||
``` | ||
### Checking whether the semaphore is locked | ||
@@ -339,7 +371,16 @@ | ||
The semaphore is considered to be locked if it has a value of zero. | ||
The semaphore is considered to be locked if its value is either zero or negative; | ||
### Setting the semaphore value | ||
The value of a semaphore can be set directly to a desired value. A positive value will | ||
cause the semaphore to schedule any pending waiters accordingly. | ||
```typescript | ||
semaphore.setValue(); | ||
``` | ||
### Cancelling pending locks. | ||
Pending locks can be cancelled by calling `cancel()` on the sempahore. This will reject | ||
Pending locks can be cancelled by calling `cancel()` on the semaphore. This will reject | ||
all pending locks with `E_CANCELED`: | ||
@@ -380,3 +421,3 @@ | ||
This works with `aquire`, too: | ||
This works with `acquire`, too: | ||
if `acquire` is used for locking, the resulting promise will reject with `E_CANCELED`. | ||
@@ -398,3 +439,3 @@ | ||
This will return a promise that resolve once the semaphore can be acquired again. This operation | ||
will not lock the semaphore, and there is no gurantee that the semaphore will still be available | ||
will not lock the semaphore, and there is no guarantee that the semaphore will still be available | ||
once a async barrier has been encountered. | ||
@@ -417,2 +458,5 @@ | ||
`waitForUnlock` accepts an optional argument `weight`. If `weight` is specified the promise | ||
will only resolve once the semaphore's value is greater or equal to weight; | ||
## Limiting the time waiting for a mutex or semaphore to become available | ||
@@ -419,0 +463,0 @@ |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
54251
868
527
Updatedtslib@^2.4.0