OpenHarmony开发者论坛

标题: OpenHarmony系统之C++线程异步回调JS机制介绍 [打印本页]

作者: 深开鸿_赵军霞    时间: 2024-4-16 09:15
标题: OpenHarmony系统之C++线程异步回调JS机制介绍
[md]# OpenHarmony系统之C++线程异步回调JS机制介绍

## 背景介绍

回调函数是 JavaScript 中常见的一种编程模式,它在异步编程中起到了重要作用。在 NAPI (Node.js API)中,回调函数也被广泛应用,用于处理各种异步操作,例如文件读写、网络请求等。按照触发源或目的线程分为JS线程、C++线程,按照回调方式分为同步回调、异步回调,本文重点介绍C++线程异步回调JS的机制。

## C++异步回调JS机制

### 机制一Async Work

首先需要进行数据定义,如下所示

![meth1_1.png](https://forums-obs.openharmony.c ... 03cuzzsxxcxgpxg.png "meth1_1.png")

![](./meth1\_1.png)

接着调用napi\_create\_async\_work接口

![meth1_2.png](https://forums-obs.openharmony.c ... 8hu8yg2emu8cjik.png "meth1_2.png")

![](./meth1\_2.png)

### 机制二Threadsafe Function

JS函数只能被JS主线程调用。如果 native 创建的其他线程需要调用 JS 函数,则需要拿到 JS 主线程的 napi\_env来调用 N-API 函数。

若native 创建的其他线程必须与 JS 主线程进行通信,线程安全函数API提供了native 创建的其他线程调用 JS 函数的方法。

#### 使用样例

回调函数定义,如下所示

![meth2_1.png](https://forums-obs.openharmony.c ... c9q1e5yu11hzto5.png "meth2_1.png")

![](./meth2\_1.png)

应用调用

![meth2_2.png](https://forums-obs.openharmony.c ... 5hxkakpvhkkf5mj.png "meth2_2.png")

![](./meth2\_2.png)

#### 使用步骤

线程安全函数的使用步骤是,先 napi\_create\_threadsafe\_function 创建函数引用, napi\_call threadsafe\_function 通过这个函数引用调用线程安全函数。

![meth2_3.png](https://forums-obs.openharmony.c ... 685hkcbh6xbcf2b.png "meth2_3.png")

![](./meth2\_3.png)

#### 机制说明

napi create threadsafe\_function 是通过创建 uv \_async 实例 &async 并绑定 AsyncCb, 再在其他线程中调用napi\_call\_threadsafe\_function(tsfn) 后 (tsfn数据结构包含&async),使用 uv\_async\_send(&async) 唤醒持有async的 JS 主线程消息队列,并调用async的回调 AsyncCb->call js\_cb()。

![meth2_4.png](https://forums-obs.openharmony.c ... 9ffq805b5ffso7f.png "meth2_4.png")

#### 注意事项

1.napi\_release\_threadsafe\_function 最后一个参数为napi\_tsfn\_abort时,会立即关闭线程安全函数,导致JS主线程无法回调函数;

2.如果创建的线程安全函数的最大队列大小为0,则Napi\_call\_threadsafe\_function()永远不会阻塞。

3.napi\_call\_threadsafe\_function()不应该在JS线程的napi\_tsfn\_blocking中调用,因为如果队列满了,它可能会导致JavaScript线程死锁。

### 机制三uv\_queue\_work

首先需要进行数据定义,如下所示

![meth3_1.png](https://forums-obs.openharmony.c ... xskhxnunskzs5xx.png "meth3_1.png")

![](./meth3\_1.png)

接着调用uv\_queue\_work接口

![meth3_2.png](https://forums-obs.openharmony.c ... i99jaws44nf24if.png "meth3_2.png")

![](./meth3\_2.png)

## 总结

### 相同点

机制一async\_Work 、机制二Threadsafe Function(简称tsfn)、机制三uv\_queue\_work
使用场景逻辑一致,都是在其他线程主函数运行时,回到 JS 主线程,并将回调函数, push 到 JS 主线程的 event-loop队列里等待被执行。

### 不同点

1.创建的线程不一样: 机制一Napi Async Work 在 queue async work 时会自己创建线程,这个线程属于 Libuv线程池,和 JS主线程一样具有 event-loop 和 napi\_env。机制二tsfn、机制三uv\_queue\_work其他线程处理时开发自己创建新线程,一般根据业务需要创建的,不在Libuv 线程池中,也没有 JS 主线程的特性。

2.JS 主线程的回调函数被执行得到时机、效率不一致:机制一async\_Work 、机制三uv\_queue\_work必须等到新创建的线程主函数被执行完后,被动被执行,只能被调用一次;机制二tsfn的回调函数在其他线程中,可以在任意时机主动调用任意次数,而且不用依赖其他函数。Napi\_Async\_Work 的使用场景是Napi\_Threadsafe\_Function 使用场景的子集,但是 Napi\_Async\_Work 无需开发者创建线程,并且线程具有 event-loop 和 napi\_env 特性。
[/md]




欢迎光临 OpenHarmony开发者论坛 (https://forums.openharmony.cn/) Powered by Discuz! X3.5