鸿蒙多线程开发——线程间数据通信对象02

1、前 言

本文的讨论是接续鸿蒙多线程开发------线程间数据通信对象01的讨论。在上一篇文章中,我们讨论了常规的JS对象(普通JSON对象、Object、Map、Array等)、ArrayBuffer。其中讨论了ArrayBuffer的复制传输和转移传输方式。

下面,我们将讨论SharedArrayBuffer。

2、SharedArrayBuffer

SharedArrayBuffer是一种允许多个线程共享相同内存空间的数据通信对象。

这意味着不同的线程可以同时访问和修改相同的数据,而无需复制数据或担心数据同步的问题。SharedArrayBuffer允许我们以更有效的方式进行多线程编程,从而提高性能。

除了SharedArrayBuffer可以直接在多个线程中直接共享外,其他与ArrayBuffer非常类似。

由于SharedArrayBuffer可以在多个线程中直接共享,因此,使用SharedArrayBuffer需要格外小心,以确保线程之间的同步和数据访问是正确的。不正确的访问可能导致内存安全性问题。

为了保证操作的原子性,我们需要使用Atomics类来对数据进行操作。

👉🏻 Atomics

与一般的全局对象不同,Atomics 不是构造函数。我们不能将其与 new 运算符一起使用或将 Atomics 对象作为一个函数来进行调用。

Atomics 的所有属性和方法都是静态的(与 Math 对象一样)。

当SharedArrayBuffer内存被共享时,多个的线程能够读写内存上的同一数据。Atomics原子操作会确保正在读或写的数据的值是符合预期的(即下一个原子操作一定会在上一个原子操作结束后才会开始,其操作不会被中断)。

Atomics提供wait()和notify()机制,采用的是 Linux 上的 futex 模型("快速用户空间互斥体"),可以让进程一直等待直到某个特定的条件为真,主要用于实现阻塞。

Atomics有如下静态方法,用于实现数据的原子操作:

  • Atomics.add(typedArray, index, value)

    将给定的值与数组上指定位置的元素相加,并返回相加前该元素的值。

  • Atomics.and(typedArray, index, value)

    将指定位置上的数组元素与给定的值相与,并返回与操作前该元素的值。

  • Atomics.compareExchange(typedArray, index, expectedValue, replacementValue)

    如果数组中指定的元素与给定的值相等,则将其更新为新的值,并返回该元素原先的值。

  • Atomics.exchange(typedArray, index, value)

    将数组中指定的元素更新为给定的值,并返回该元素更新前的值。

  • Atomics.load(typedArray, index)

    返回数组中指定元素的值。

  • Atomics.notify(typedArray, index, count)

    通知正在等待数组指定索引的代理。返回收到通知的代理数量。

  • Atomics.or(typedArray, index, value)

    将指定位置上的数组元素与给定的值相或,并返回或操作前该元素的值。

  • Atomics.store(typedArray, index, value)

    将值储存到数组的指定位置,并返回该值。

  • Atomics.sub(typedArray, index, value)

    将指定位置上的数组元素与给定的值相减,并返回相减前该元素的值。

  • Atomics.wait(typedArray, index, value, timeout)

    检测数组中某个指定位置上的值是否仍然是给定值,是则保持挂起直到被唤醒或超时。返回值为 "ok"、"not-equal" 或 "time-out"。调用时,如果当前代理不允许阻塞,则会抛出异常(大多数浏览器都不允许在主线程中调用 wait())。

  • Atomics.waitAsync(typedArray, index, value, timeout)

    在共享内存位置上异步等待(即没有阻塞,与 Atomics.wait 不同)并返回一个 Promise。

  • Atomics.xor(typedArray, index, value,)

    将指定位置上的数组元素与给定的值相异或,并返回异或操作前该元素的值。

Atomics的基本使用示例如下:

复制代码
const sab = new SharedArrayBuffer(1024);const ta = new Uint8Array(sab);ta[0]; // 0ta[0] = 5; // 5Atomics.add(ta, 0, 12); // 5Atomics.load(ta, 0); // 17Atomics.and(ta, 0, 1); // 17Atomics.load(ta, 0); // 1Atomics.compareExchange(ta, 0, 5, 12); // 1Atomics.load(ta, 0); // 1Atomics.exchange(ta, 0, 12); // 1Atomics.load(ta, 0); // 12Atomics.or(ta, 0, 1); // 12Atomics.load(ta, 0); // 13Atomics.store(ta, 0, 12); // 12Atomics.sub(ta, 0, 2); // 12Atomics.load(ta, 0); // 10Atomics.xor(ta, 0, 1); // 10Atomics.load(ta, 0); // 11

Atomics等待和通知机制

假设有一个SharedArrayBuffer共享内存。如下:​​​​​​​

复制代码
const sab = new SharedArrayBuffer(1024);const int32 = new Int32Array(sab);

A线程关键代码如下:​​​​​​​

复制代码
Atomics.wait(int32, 0, 0);consle.log(int32[0]); // 123

由于默认情况下,int32[0]值为0,因此A线程将在代码1行上进行阻塞等待。

此时如果启动了B线程,关键代码如下:​​​​​​​

复制代码
console.log(int32[0]); // 0;Atomics.store(int32, 0, 123);Atomics.notify(int32, 0, 1);

B线程启动后,第一行代码可以如期打印出初始化的0,紧接着,向SharedArrayBuffer中第0号位,写入了123,然后再调用了notify,发送出一个解锁通知。

A线程中第1行代码的wait在收到通知后,发现0号位已经不等于0了,则执行下一行代码,打印出了B线程写入的123。

示意图如下:

由于篇幅原因Transferable、Sendable我们在后面介绍。

相关推荐
香蕉可乐荷包蛋42 分钟前
vue 常见ui库对比(element、ant、antV等)
javascript·vue.js·ui
__Benco1 小时前
OpenHarmony - 小型系统内核(LiteOS-A)(完),内核编码规范
人工智能·harmonyos
Bruce_Liuxiaowei9 小时前
HarmonyOS Next~鸿蒙系统流畅性技术解析:预加载与原生架构的协同进化
华为·架构·harmonyos
大飞pkz14 小时前
【Unity】如何解决UI中的Button无法绑定带参数方法的问题
ui·unity·游戏引擎·游戏开发·开发记录·button绑定
特立独行的猫a17 小时前
HarmonyOS NEXT 诗词元服务项目开发上架全流程实战(二、元服务与应用APP签名打包步骤详解)
华为·打包发布·harmonyos·应用签名·appgallery
A富得流油的咸鸭蛋19 小时前
harmonyOS 手机,双折叠,平板,PC端屏幕适配
智能手机·电脑·harmonyos
周胡杰20 小时前
鸿蒙文件上传-从前端到后端详解,对比jq请求和鸿蒙arkts请求区别,对比new FormData()和鸿蒙arktsrequest.uploadFile
前端·华为·harmonyos·鸿蒙·鸿蒙系统
唯鹿20 小时前
AI生成Flutter UI代码实践(一)
人工智能·flutter·ui
code_shenbing1 天前
WPF实现类似Microsoft Visual Studio2022界面效果及动态生成界面技术
ui·c#·wpf·上位机
UI设计兰亭妙微2 天前
大屏 UI 设计:解锁视觉盛宴的奥秘
ui