@dhlx/rwlock-shared
Version:
A simple implementation of a read-write lock with shared read
96 lines (95 loc) • 3.3 kB
JavaScript
var l = Object.defineProperty;
var w = (i, t, s) => t in i ? l(i, t, { enumerable: !0, configurable: !0, writable: !0, value: s }) : i[t] = s;
var a = (i, t, s) => w(i, typeof t != "symbol" ? t + "" : t, s);
const n = (i) => new Promise((t) => setTimeout(t, i)), e = class e {
constructor(t, s = {}) {
a(this, "state");
a(this, "timeout", 500);
this.state = new Int32Array(t), this.timeout = s.timeout || this.timeout;
}
/** Acquire a read lock (async). Blocks if a writer is active or waiting. */
async readLock() {
for (; ; ) {
const t = Atomics.load(this.state, e.WRITER), s = Atomics.load(this.state, e.WAITERS);
if (t === 0 && s === 0) {
Atomics.add(this.state, e.READERS, 1);
return;
}
await Atomics.waitAsync(this.state, e.WRITER, 0, this.timeout).value, await n(0);
}
}
/** Release a read lock. Wakes a waiting writer if this was the last reader. */
readUnlock() {
Atomics.sub(this.state, e.READERS, 1), Atomics.load(this.state, e.WAITERS) > 0 && Atomics.notify(this.state, e.READERS);
}
/** Acquire a write lock (async). Blocks until no readers or writers are active. */
async writeLock() {
for (Atomics.add(this.state, e.WAITERS, 1); ; ) {
const t = Atomics.load(this.state, e.READERS);
if (t === 0 && Atomics.compareExchange(this.state, e.WRITER, 0, 1) === 0)
break;
t > 0 ? await Atomics.waitAsync(
this.state,
e.READERS,
0,
this.timeout
).value : await Atomics.waitAsync(
this.state,
e.WRITER,
0,
this.timeout
).value, await n(0);
}
Atomics.sub(this.state, e.WAITERS, 1);
}
/** Release the write lock. Wakes the next waiter(s) based on priority. */
writeUnlock() {
Atomics.store(this.state, e.WRITER, 0), Atomics.load(this.state, e.WAITERS) > 0 ? Atomics.notify(this.state, e.WRITER, 1) : Atomics.notify(this.state, e.WRITER, Number.POSITIVE_INFINITY);
}
};
// Index constants for clarity
a(e, "READERS", 0), a(e, "WRITER", 1), a(e, "WAITERS", 2);
let c = e;
class E {
constructor(t, s) {
a(this, "lock");
a(this, "dataBuffer");
a(this, "dataView");
this.lock = new c(s), this.dataBuffer = t, this.dataView = new DataView(t);
}
// 安全读取数据
async readData() {
await this.lock.readLock();
const t = this.deserialize();
return this.lock.readUnlock(), t;
}
// 安全写入数据
async writeData(t) {
try {
await this.lock.writeLock();
const s = this.deserialize(), r = t(s);
this.serialize(r);
} finally {
this.lock.writeUnlock();
}
}
serialize(t) {
const s = JSON.stringify(t), o = new TextEncoder().encode(s);
this.dataView.setUint32(0, o.length), o.forEach((h, d) => this.dataView.setUint8(4 + d, h));
}
deserialize() {
const t = this.dataView.getUint32(0), s = new Uint8Array(this.dataBuffer.slice(4, t + 4)), r = new Uint8Array(s), o = new TextDecoder();
return o.decode(r) ? JSON.parse(o.decode(r) ?? "{}") : {};
}
}
function u(i = Int32Array.BYTES_PER_ELEMENT * 3, t = 1024) {
return {
lockBuffer: new SharedArrayBuffer(i),
dataBuffer: new SharedArrayBuffer(t)
};
}
export {
c as ReadWriteLock,
E as SharedData,
u as createSharedBuffers
};