Monitorクラス
稀ではあるが、JavascriptでCtirical Section的なものを導入したくなる時がある。
同期方法の一種であるMonitor を実現するMonitorクラスを作ってみた。
function Monitor(){
this.promises = [];
this.resolvers = [];
}
Monitor.prototype.enter = function(){
this.promises.push(new Promise((res,rej)=>{ this.resolvers.push(res); })); // This promise is for the next waiter
return this.promises.length == 1 ? Promise.resolve(true) : this.promises[this.promises.length-2];
};
Monitor.prototype.exit = function(){
if(this.promises.length<=0) return; // Invalid use of exit
this.resolvers[0](true); // Invoke the first waiter
this.promises.shift();
this.resolvers.shift();
};
使い方
atomicにしたい処置をawait monitor.enter(), monitor.exit()で囲む。await monitor.enter()は他にCritical Sectionに入っている処理がある場合、それが終わるまでブロックする。Javascriptはシングルスレッドなのでatomicに処理したい部分の少なくとも一箇所は、非同期に実行している一連のコード(thenチェーン)になるでしょう。
例
money=10000円に対して1000円減らして2000円足す、という処理が何らかの理由で非同期で実行されていてかつ不可分に実施する必要がある場合(つまり、money=9000円の状態で参照されてはならない).
// Monitor object
var monitor = new Monitor();
//....
// Part A
await monitor.enter();
var money = 10000;
doSomething()
.then(()=>{
money -= 1000;
})
.then(()=>{
money += 2000;
})
.finally(()=>{
monitor.exit();
});
// .... 別の場所 ....
// Part B
await monitor.enter();
if(money >= 10000)
console.log("お金足りるよ");
else
console.log("お金足りないよ");
monitor.exit();