Help us understand the problem. What is going on with this article?

SharedMemory と Atomic API について

More than 3 years have passed since last update.

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
nijibox
ニジボックスの開発は、社内のUI/UXデザインチームと連携をとりながらワンストップで行う開発支援サービスです。Reactを始めPHP(Laravel)・Ruby on Rails、Swift・Kotlinを使った開発実績も多く、バックエンドからアプリまで幅広く対応しています。Twitterで情報発信しています: https://twitter.com/nijibox_jp
https://nijibox.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした