[经验分享] OpenHarmony系统之C++线程异步回调JS机制介绍 精华

赵军霞 显示全部楼层 发表于 2024-4-16 09:15:18

OpenHarmony系统之C++线程异步回调JS机制介绍

背景介绍

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

C++异步回调JS机制

机制一Async Work

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

meth1_1.png

接着调用napi_create_async_work接口

meth1_2.png

机制二Threadsafe Function

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

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

使用样例

回调函数定义,如下所示

meth2_1.png

应用调用

meth2_2.png

使用步骤

线程安全函数的使用步骤是,先 napi_create_threadsafe_function 创建函数引用, napi_call threadsafe_function 通过这个函数引用调用线程安全函数。

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

注意事项

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

接着调用uv_queue_work接口

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 特性。

©著作权归作者所有,转载或内容合作请联系作者

您尚未登录,无法参与评论,登录后可以:
参与开源共建问题交流
认同或收藏高质量问答
获取积分成为开源共建先驱

Copyright   ©2023  OpenHarmony开发者论坛  京ICP备2020036654号-3 |技术支持 Discuz!

返回顶部