// Simple async mutex for JS environments
class Mutex {
constructor(){ this.q = []; this.locked = false; }
lock(){
return new Promise(res => {
if (!this.locked){ this.locked = true; res(this._unlock.bind(this)); }
else this.q.push(res);
});
}
_unlock(){
if (this.q.length){ const next = this.q.shift(); next(this._unlock.bind(this)); }
else { this.locked = false; }
}
}
// Condition variable sketch (pair with mutex)
class CondVar {
constructor(){ this.waiters = []; }
wait(m){
return new Promise(async res => { this.waiters.push(res); const unlock = await m.lock(); unlock(); });
}
notifyOne(){ const w = this.waiters.shift(); if (w) w(); }
notifyAll(){ while(this.waiters.length) this.waiters.shift()(); }
}
// Counting semaphore
class Semaphore {
constructor(count){ this.count = count; this.q = []; }
async acquire(){
if (this.count > 0){ this.count--; return; }
await new Promise(res => this.q.push(res));
}
release(){
if (this.q.length) this.q.shift()();
else this.count++;
}
}
// Classic producer-consumer with bounded buffer uses two semaphores (empty/full) + a mutex
// RCU-like idea in JS (no true threads): versioned pointer swap
let ptr = {version:0, data: {}};
function rcuRead(){ return ptr; } // readers snapshot the reference
function rcuUpdate(mutator){
const cur = ptr; const next = {version: cur.version+1, data: structuredClone(cur.data)};
mutator(next.data);
ptr = next; // publish
// defer reclamation of 'cur' until all readers drop (not modeled here)
}