Skip to content

Instantly share code, notes, and snippets.

@jdmichaud
Last active September 30, 2019 07:15
Show Gist options
  • Save jdmichaud/10bc5af316b78f7300cf96eae00a76ce to your computer and use it in GitHub Desktop.
Save jdmichaud/10bc5af316b78f7300cf96eae00a76ce to your computer and use it in GitHub Desktop.
A mutex++ in javascript
async function main() {
const throttler = new Throttler();
const lock = await throttler.throttle();
console.log('first lock taken');
setTimeout(() => {
console.log('releasing first lock');
lock.release();
}, 2000);
setTimeout(async () => {
console.log('About to take third lock');
try {
const lock3 = await throttler.throttle();
console.log('lock3 done waiting');
lock3.release();
const lock4 = await throttler.throttle();
console.log('lock4 went through');
} catch (e) { console.log('lock2 cancelled', e); }
}, 1000)
try {
console.log('About to take second lock');
const lock2 = await throttler.throttle();
console.log('lock2 done waiting');
} catch (e) { console.log('lock2 cancelled', e); }
}
window.onload = main()
function Mutex() {
// A promise representing a lock given to the running thread.
// The thread will be in charge of releasing the lock once done.
this.lockPromise = undefined;
// An object containing a release and reject method which controls the promise
// provided to the blocked thread.
this.block = undefined;
// Create the lock and return it.
function createLock() {
const lock = {};
this.lockPromise = new Promise(resolve => {
lock.release = resolve;
});
return lock;
}
return {
throttle: async () => {
if (this.lockPromise === undefined) {
// No lock yet, then just create a resolved promise and return it.
const promise = Promise.resolve(createLock.apply(this));
this.lockPromise.then(() => {
// The running thread just released the lock, then if a thread was
// waiting, release it and provide it a new lock.
if (this.block !== undefined) {
this.block.release(Promise.resolve(createLock()));
this.block = undefined;
}
this.lockPromise = undefined;
});
return promise;
} else {
if (this.block !== undefined) {
// Reject the previous waiting thread.
this.block.reject();
}
const promise = new Promise((resolve, reject) => {
this.block = {
release: resolve,
reject: reject,
};
});
return promise;
}
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment