UNPKG

@dhlx/rwlock-shared

Version:

A simple implementation of a read-write lock with shared read

96 lines (95 loc) 3.3 kB
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 };