ノンブロッキングな平行処理

いわゆるトランザクションスタイルで行うプログラミングのサポートの記事。


普通平行プログラミングで採用されるロックスタイルというのは、あらかじめリソースロックを確保してから排他的に処理を行いロックを解除するスタイル。

getLocks(...);
doProcessing();
releaseLocks(...);

このスタイルでの工夫としては、ロックデータを小さくする、ロック期間を短くする、ロックの種類によって処理を変える(Reader-Writer Lock)など。


一方トランザクションスタイルは、その時点のスナップショットデータ値を取り出し、ふそのまま処理する。ただし更新だけ特別に処理を行う。

int data = atomic.getAtomic();
int updated = doProcessing(data);
boolean success = atomic.tryUpdate(data, updated);
if (!success) retry;

更新処理では、値を取り出した後、更新値を計算する。取り出した時点の値と現状の更新データの値を値比較し、元データのままであればアトミックに更新処理する。元データから変わっていたら失敗し、たとえば普通はリトライ(再取得し更新値を再計算)をするし、あるいは更新をあきらめてもしまっていい処理もある。


トランザクション処理は、更新データの計算が小さい場合や、更新より参照が圧倒的に多い場合などで有効。逆に平行更新が頻繁に起きる場合などは失敗が多くなりパフォーマンスは下がる。またロックは同一メモリじゃないととたんにコスト高(とりわけデッドロック回避で)になるが、トランザクションは分散処理でも変わらない。


STMも本来はこういうスタイルで処理できるために実装されている。

atomic内で全部処理しちゃうと、ロックと一緒だけれど。