sharedarraybuffer 配合 atomics.wait/notify 实现跨 worker 高频同步,核心是“值匹配+显式唤醒”,需满足跨域隔离、使用 int32array、避免 notify 先于 wait,并通过翻转标志位等防错设计保障可靠性。

SharedArrayBuffer 配合 Atomics.wait 实现跨 Worker 高频同步信号,核心不是“发信号”,而是“等状态变化”——它依赖一个共享整数位置的值变更来触发等待线程唤醒,必须配对使用 Atomics.notify 才能生效。直接调用 wait 不会自动响应、不会超时等待、也不能在主线程运行。
必须先满足跨域隔离环境
浏览器默认禁用 SharedArrayBuffer,不满足以下任一条件,new SharedArrayBuffer() 就会抛出 TypeError:
- 服务器响应头包含 Cross-Origin-Opener-Policy: same-origin 和 Cross-Origin-Embedder-Policy: require-corp
- 所有外部资源(
<script></script>、<iframe></iframe>、<img>等)都加 crossorigin 属性 - 本地开发不能双击打开 HTML,必须用
localhost或127.0.0.1启服务(如npx serve) - 检查是否就绪:控制台执行
self.crossOriginIsolated,返回 true 才可用
正确构造等待-通知闭环
Atomics.wait 不是定时器,也不是轮询开关。它的作用是在某个 Int32Array 索引位置的值**等于预期值**时挂起线程,直到另一方调用 notify 唤醒。关键在于“值匹配 + 显式唤醒”:
- Worker 中等待:先用 Atomics.load(view, 0) 确认当前值,再调用 Atomics.wait(view, 0, expectedValue)(第四个 timeout 参数多数浏览器忽略,不建议依赖)
- 通知方(另一个 Worker 或主线程)必须在同一视图上执行 Atomics.notify(view, 0, 1),第三个参数表示唤醒数量
- 不能先 notify 再 wait——如果 notify 发生在 wait 调用前,wait 会立即返回
"not-equal",无法捕获信号 - 务必用 Int32Array 视图;传入 Float64Array 或 Uint8Array 会报 RangeError
高频场景下的防错设计
高频同步容易因竞争或误用导致信号丢失、死锁或 CPU 占满:
- 避免自旋等待:不要写 while (Atomics.load(view, 0) === 0) {},改用 wait + notify 组合,否则单个 Worker 可能吃满一个核
- 每次 wait 后需重新 load 判断状态,因为 notify 唤醒后值可能已被其他 Worker 修改
- 若需重复触发(比如每帧通知),推荐用“翻转标志位”模式:约定 0→1 表示新事件,收到后立刻 store 回 0,下次再变 1,避免多次 notify 被合并
- 多个 Worker 同时 wait 同一位置时,notify(n) 只唤醒前 n 个,其余继续挂起;如需广播,设 n 为大数(如 100)或循环 notify
完整最小可运行示例
主线程初始化并启动两个 Worker,Worker A 计算完通知 Worker B:
- 主线程:
const sab = new SharedArrayBuffer(4); const iv = new Int32Array(sab); Atomics.store(iv, 0, 0); workerA.postMessage({sab}); workerB.postMessage({sab}); - Worker A:
Atomics.store(iv, 0, 1); Atomics.notify(iv, 0, 1); - Worker B:
Atomics.wait(iv, 0, 0); console.log('收到同步信号');
注意:Worker B 必须在主线程调用 notify 之后 才执行 wait,否则会立即返回失败。实际中建议用 postMessage 协调初始时机,或让 B 先 sleep 几毫秒再 wait。











