LoginSignup
26
15

More than 5 years have passed since last update.

SharedMemory と Atomic API について

Last updated at Posted at 2015-12-19

SharedMemory と Atomic API について

このエントリは JavaScript stage 0,1,2,3 Advent Calendar 2015 の 19日目の記事です。

ちなみに stage 1 です。

image

SharedMemory は SharedArrayBuffer と呼ばれる特殊な ArrayBuffer をインタフェースにして提供されます。さらに、 Atomic API というのはこの SharedArrayBuffer を操作するための Atomic という built-in Object です。

ちなみに Node.js v4.0 以降なら --harmony-sharedarraybuffer--harmony-atomics で有効になります。 (Worker がないので無意味ですが)

背景

基本的に WebWorker に代表される Worker は shared nothing、 つまりメモリを共有せず、値をコピーしてpostMessageなどでWorker間で協調しながら値を共有してきました。

このやり方はシンプルですが、コピーせず Worker 間でメモリを共有できたほうが効率的です(もちろん共有するな協調せよという考え方もあります)。

また SharedArrayBuffer を扱うためにはWorker間でのリソースの競合を防ぐ必要があります。これを可能にするために入っているのが Atomic API です。

こちらは SharedArrayBufferで作った配列に対して Atomic な操作を提供します。配列に対してadd/sub/and/or等の操作をする際に他のWorkerが操作していないか確認しロックを取る仕組みになっています。仕様によれば、futexの仕組みを使ってロックを取ると記述があります。

SharedArrayBuffer を共通化する

// main.js
var worker = new Worker("worker.js");
var sab = new SharedArrayBuffer(1024); 

worker.onmessage = function(e) {
  console.log(e.data);
};

worker.postMessage(sab, [sab]);
// worker

var sab;
onmessage = function (ev) {
   sab = ev.data; // data が共有化される。
}

こんな感じで SharedArrayBuffer を共有します。直接 data の配列を変更すると値が修正されます。ただしその場合、 Atomic な操作じゃないので別な worker が変更してしまうと競合が発生する可能性があります。

競合を回避するのが Atomic API です。 Atomic API は下記のようにして使います。

Atomic API

// SharedArrayBuffer and Atomics
// use flag --harmony-sharedarraybuffer --harmony-atomics

var sab = new SharedArrayBuffer(4); // SharedArrayBufferを作る
var uint8Array = new Uint8Array(sab); // Integer Shared Typed Array になる
for (i = 0; i < 4; i++) {
  uint8Array[i] = i;
}

uint8Array.forEach((x) => console.log(x)); // 0, 1, 2, 3

Atomics.add(uint8Array, 2, 10); // index 2 に 10 を足す
Atomics.sub(uint8Array, 3, 3); // index 3 から 3 を引く
Atomics.compareExchange(uint8Array, 0, 0, 1); // index 0 が 0 なら 1 にする
uint8Array.forEach((x) => console.log(x)); // 1, 1, 12, 0

console.log(Atomics.load(uint8Array, 2)); // 12 index 2 の値を get する
console.log(Atomics.store(uint8Array, 2, 19)); // 19 index 2 の値を19に書き換えて書き換えた値をgetする
uint8Array.forEach((x) => console.log(x)); // 1, 1, 19, 0
26
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
15