Skip to content

Commit 17d24e6

Browse files
committed
docs(arrayBuffer): edit sharedBuffer
1 parent 24b5330 commit 17d24e6

File tree

2 files changed

+100
-21
lines changed

2 files changed

+100
-21
lines changed

docs/arraybuffer.md

Lines changed: 96 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -975,6 +975,8 @@ bitmap.pixels = new Uint8Array(buffer, start);
975975

976976
## SharedArrayBuffer
977977

978+
### 共享内存
979+
978980
JavaScript 是单线程的,Web worker 引入了多线程:主线程用来与用户互动,Worker 线程用来承担计算任务。每个线程的数据都是隔离的,通过`postMessage()`通信。下面是一个例子。
979981

980982
```javascript
@@ -1029,7 +1031,13 @@ Worker 线程从事件的`data`属性上面取到数据。
10291031
// Worker 线程
10301032
var sharedBuffer;
10311033
onmessage = function (ev) {
1032-
sharedBuffer = ev.data; // 1KB 的共享内存,就是主线程共享出来的那块内存
1034+
// 主线程共享的数据,就是 1KB 的共享内存
1035+
const sharedBuffer = ev.data;
1036+
1037+
// 在共享内存上建立视图,方便读写
1038+
const sharedArray = new Int32Array(sharedBuffer);
1039+
1040+
// ...
10331041
};
10341042
```
10351043

@@ -1067,6 +1075,8 @@ onmessage = function (ev) {
10671075
};
10681076
```
10691077

1078+
### Atomics 对象
1079+
10701080
多线程共享内存,最大的问题就是如何防止两个线程同时修改某个地址,或者说,当一个线程修改共享内存以后,必须有一个机制让其他线程同步。SharedArrayBuffer API 提供`Atomics`对象,保证所有共享内存的操作都是“原子性”的,并且可以在所有进程内同步。
10711081

10721082
```javascript
@@ -1085,7 +1095,90 @@ Atomics.add(ia, 112, 1); // 正确
10851095

10861096
上面代码中,Worker 线程直接改写共享内存是不正确的。有两个原因,一是可能发生两个线程同时改写该地址,二是改写以后无法同步到其他 Worker 线程。所以,必须使用`Atomics.add()`方法进行改写。
10871097

1088-
下面是另一个例子。
1098+
`Atomics`提供多种方法。
1099+
1100+
**(1)Atomics.store(),Atomics.load()**
1101+
1102+
`store()`方法用来向共享内存写入数据,`load()`方法用来从共享内存读出数据。比起直接的读写操作,它们的好处是保证了读写操作的安全性。比如有时编译器为了优化,会改变某些操作的执行顺序,从而导致其他线程读取时出现问题,`store``load`就保证了编辑器不会改变这些操作。
1103+
1104+
```javascript
1105+
Atomics.load(array, index)
1106+
Atomics.store(array, index, value)
1107+
```
1108+
1109+
`store`方法接受三个参数:SharedBuffer 的视图、位置索引和值,返回`sharedA[index]`的值。`load`方法只接受两个参数:SharedBuffer 的视图和位置索引,也是返回`sharedArray[index]`的值。
1110+
1111+
```javascript
1112+
// 主线程 main.js
1113+
console.log('notifying...');
1114+
Atomics.store(sharedArray, 0, 123);
1115+
1116+
// Worker 线程 worker.js
1117+
while (Atomics.load(sharedArray, 0) !== 123) ;
1118+
console.log('notified');
1119+
```
1120+
1121+
上面代码中,主线程的`Atomics.store`向 SharedBuffer 视图的0号位置,写入123。Worker 线程的`Atomics.load`从该位置读出数据,只要不等于123就不断循环。
1122+
1123+
**(2)Atomics.wait(),Atomics.wake()**
1124+
1125+
使用`while`循环等待主线程的通知,不是很高效,`Atomics`对象提供了`wait()``wake()`两个方法用于等待通知。
1126+
1127+
```javascript
1128+
Atomics.wait(sharedArray, index, value, time)
1129+
```
1130+
1131+
`Atomics.wait`用于当`sharedArray[index]`不等于`value`,就返回`not-equal`,否则就进入休眠,只有使用`Atomics.wake()`或者`time`毫秒以后才能唤醒。被`Atomics.wake()`唤醒时,返回`ok`,超时唤醒时返回`timed-out`
1132+
1133+
```javascript
1134+
Atomics.wake(sharedArray, index, count)
1135+
```
1136+
1137+
`Atomics.wake`用于唤醒`count`数目在`sharedArray[index]`位置休眠的线程,让它继续往下运行。
1138+
1139+
**(3)运算方法**
1140+
1141+
共享内存上面的某些运算是不能被打断的,即不能在运算过程中,让其他线程改写内存上面的值。Atomics 对象提供了一些运算方法,防止数据被改写。
1142+
1143+
```javascript
1144+
Atomics.add(sharedArray, index, value)
1145+
```
1146+
1147+
`Atomics.add`用于将`value`加到`sharedArray[index]`,返回`sharedArray[index]`旧的值。
1148+
1149+
```javascript
1150+
Atomics.sub(sharedArray, index, value)
1151+
```
1152+
1153+
`Atomics.sub`用于将`value``sharedArray[index]`减去,返回`sharedArray[index]`旧的值。
1154+
1155+
```javascript
1156+
Atomics.and(sharedArray, index, value)
1157+
```
1158+
1159+
`Atomics.and`用于将`value``sharedArray[index]`进行位运算`and`,放入`sharedArray[index]`,并返回旧的值。
1160+
1161+
```javascript
1162+
Atomics.or(sharedArray, index, value)
1163+
```
1164+
1165+
`Atomics.or`用于将`value``sharedArray[index]`进行位运算`or`,放入`sharedArray[index]`,并返回旧的值。
1166+
1167+
```javascript
1168+
Atomics.xor(sharedArray, index, value)
1169+
```
1170+
1171+
`Atomic.xor`用于将`vaule``sharedArray[index]`进行位运算`xor`,放入`sharedArray[index]`,并返回旧的值。
1172+
1173+
**(4)其他方法**
1174+
1175+
`Atomics`对象还有以下方法。
1176+
1177+
- `Atomics.compareExchange(sharedArray, index, oldval, newval)`:如果`sharedArray[index]`等于`oldval`,就写入`newval`,返回`oldval`
1178+
- `Atomics.exchange(sharedArray, index, value)`:设置`sharedArray[index]`的值,返回旧的值。
1179+
- `Atomics.isLockFree(size)`:返回一个布尔值,表示`Atomics`对象是否可以处理某个`size`的内存锁定。如果返回`false`,应用程序就需要自己来实现锁定。
1180+
1181+
### Atomics 对象的例子
10891182

10901183
```javascript
10911184
// 线程一
@@ -1098,20 +1191,5 @@ Atomics.wait(ia, 37, 163);
10981191
console.log(ia[37]); // 123456
10991192
```
11001193

1101-
上面代码中,共享内存`ia`的第37号位置,原来的值是`163`。进程二使用`Atomics.wait()`方法,指定只要`ia[37]`等于`163`,就处于“等待”状态。进程一使用`Atomics.store()`方法,将`123456`放入`ia[37]`,然后使用`Atomics.wake()`方法将监视`ia[37]`的一个线程唤醒。
1102-
1103-
`Atomics`对象有以下方法。
1104-
1105-
- `Atomics.load(array, index)`:返回`array[index]`的值。
1106-
- `Atomics.store(array, index, value)`:设置`array[index]`的值,返回这个值。
1107-
- `Atomics.compareExchange(array, index, oldval, newval)`:如果`array[index]`等于`oldval`,就写入`newval`,返回`oldval`
1108-
- `Atomics.exchange(array, index, value)`:设置`array[index]`的值,返回旧的值。
1109-
- `Atomics.add(array, index, value)`:将`value`加到`array[index]`,返回`array[index]`旧的值。
1110-
- `Atomics.sub(array, index, value)`:将`value``array[index]`减去,返回`array[index]`旧的值。
1111-
- `Atomics.and(array, index, value)`:将`value``array[index]`进行位运算`and`,放入`array[index]`,并返回旧的值。
1112-
- `Atomics.or(array, index, value)`:将`value``array[index]`进行位运算`or`,放入`array[index]`,并返回旧的值。
1113-
- `Atomics.xor(array, index, value)`:将`vaule``array[index]`进行位运算`xor`,放入`array[index]`,并返回旧的值。
1114-
- `Atomics.wait(array, index, value, timeout)`:如果`array[index]`等于`value`,进程就进入休眠状态,必须通过`Atomics.wake()`唤醒。`timeout`指定多少毫秒之后,进入休眠。返回值是三个字符串(ok、not-equal、timed-out)中的一个。
1115-
- `Atomics.wake(array, index, count)`:唤醒指定数目在某个位置休眠的进程。
1116-
- `Atomics.isLockFree(size)`:返回一个布尔值,表示`Atomics`对象是否可以处理某个`size`的内存锁定。如果返回`false`,应用程序就需要自己来实现锁定。
1194+
上面代码中,共享内存视图`ia`的第37号位置,原来的值是`163`。进程二使用`Atomics.wait()`方法,指定只要`ia[37]`等于`163`,就进入休眠状态。进程一使用`Atomics.store()`方法,将`123456`放入`ia[37]`,然后使用`Atomics.wake()`方法将监视`ia[37]`的一个休眠线程唤醒。
11171195

docs/reference.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@
220220
- Ian Elliot, [Reading A BMP File In JavaScript](http://www.i-programmer.info/projects/36-web/6234-reading-a-bmp-file-in-javascript.html)
221221
- Renato Mangini, [How to convert ArrayBuffer to and from String](http://updates.html5rocks.com/2012/06/How-to-convert-ArrayBuffer-to-and-from-String)
222222
- Axel Rauschmayer, [Typed Arrays in ECMAScript 6](http://www.2ality.com/2015/09/typed-arrays.html)
223+
- Axel Rauschmayer, [ES proposal: Shared memory and atomics](http://2ality.com/2017/01/shared-array-buffer.html)
223224

224225
## SIMD
225226

@@ -239,7 +240,7 @@
239240
- army8735, [Javascript Downcast](https://github.com/army8735/jsdc): 国产的ES6到ES5的转码器
240241
- esnext, [ES6 Module Transpiler](https://github.com/esnext/es6-module-transpiler):基于node.js的将ES6模块转为ES5代码的命令行工具
241242
- Sebastian McKenzie, [BabelJS](http://babeljs.io/): ES6转译器
242-
- SystemJS, [SystemJS](https://github.com/systemjs/systemjs): 在浏览器中加载AMD、CJS、ES6模块的一个垫片库
243-
- Modernizr, [HTML5 Cross Browser Polyfills](https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills#ecmascript-6-harmony): ES6垫片库清单
244-
- Facebook, [regenerator](https://github.com/facebook/regenerator): 将Generator函数转为ES5的转码器
243+
- SystemJS, [SystemJS](https://github.com/systemjs/systemjs): 在浏览器中加载 AMD、CJS、ES6 模块的一个垫片库
244+
- Modernizr, [HTML5 Cross Browser Polyfills](https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills#ecmascript-6-harmony): ES6 垫片库清单
245+
- Facebook, [regenerator](https://github.com/facebook/regenerator): 将 Generator 函数转为 ES5 的转码器
245246

0 commit comments

Comments
 (0)