使用Node-API进行线程安全开发

一、Node-API线程安全机制概述

        Node-API线程安全开发主要用于异步多线程之间共享和调用场景中使用,以避免出现竞争条件或死锁。

        1、适用场景

  • 异步计算:如果需要进行耗时的计算或IO操作,可以创建一个线程安全函数,将计算或IO操作放在另一个线程中执行,避免阻塞主线程,提高程序的响应速度。
  • 数据共享:如果多个线程需要访问同一份数据,可以创建一个线程安全函数,确保数据的读写操作不会发生竞争条件或死锁等问题。
  • 多线程开发:如果需要进行多线程开发,可以创建一个线程安全函数,确保多个线程之间的通信和同步操作正确无误。

        2、总体步骤

        Node-API接口只能在ArkTS主线程上进行调用。当C++子线程或者work子线程需要调用ArkTS回调接口或者Node-API接口时,这些线程是需要与ArkTS主线程进行通信才能完成的。Node-API提供了类型napi_threadsafe_function(线程安全函数)以及创建、销毁和调用该类型对象的 API来完成此操作。Node-API主要是通过创建一个线程安全函数,然后在C++子线程或者work子线程中调用线程安全函数来实现线程安全开发。

        步骤如下:

  1. 在Native接口函数中,创建一个线程安全函数对象,并注册绑定ArkTS回调接口callback和线程安全回调函数call_js_cb,然后立即返回一个临时结果给ArkTS调用者;
  2. 通过系统调度C++子线程完成异步业务逻辑的执行,并在子线程的执行函数中调用napi_call_threadsafe_function,将call_js_cb抛给EventLoop事件循环进行调度;
  3. 通过call_js_cb执行,调用napi_call_function调用ArkTS回调接口callback,从而将异步计算结果反馈到ArkTS应用侧,用于应用侧UI刷新。

        3、原理流程 

        线程安全函数的底层机制依然是基于libuv异步库来实现的。

        4、关键接口 

        线程安全函数机制中关键的两个接口napi_create_threadsafe_function()和napi_call_threadsafe_function()。

        (1)napi_create_threadsafe_function

        该接口主要用于创建线程安全对象,在创建的过程中,会注册异步过程中的关键信息:ArkTS侧回调接口callback、线程安全回调函数call_js_cb等。

NAPI_EXTERN napi_status napi_create_threadsafe_function(napi_env env,napi_value func,napi_value async_resource,napi_value async_resource_name,size_t max_queue_size,size_t initial_thread_count,void* thread_finalize_data,napi_finalize thread_finalize_cb,void* context,napi_threadsafe_function_call_js call_js_cb,napi_threadsafe_function* result);
参数说明:
[in] env:传入接口调用者的环境,包含方舟引擎等。由框架提供,默认情况下直接传入即可。
[in] func:ArkTS应用侧传入的回调接口callback,可为空。当该值为nullptr时,下文call_js_cb不能为nullptr。反之,亦然。两者不可同时为空。
[in] async_resource:关联async_hooks,可为空。
[in] async_resource_name:异步资源标识符,主要用于async_hooks API暴露断言诊断信息。
[in] max_queue_size:缓冲队列容量,0表示无限制。线程安全函数实现实质为生产者-消费者模型。
[in] initial_thread_count:初始线程,包括将使用此函数的主线程,可为空。
[in] thread_finalize_data:传递给thread_finalize_cb接口的参数,可为空。
[in] thread_finalize_cb:当线程安全函数结束释放时的回调接口,可为空。
[in] context:附加的上下文数据,可为空。
[in] call_js_cb:子线程需要处理的线程安全回调任务,类似于异步工作项中的complete回调。当调用napi_call_threadsafe_function后,被抛到ArkTS主线程EventLoop中,等待调度执行。当该值为空时,系统将会调用默认回调接口。
[out] result:线程安全函数对象指针。

        (2)napi_call_threadsafe_function

        该接口主要用于子线程中,将需要回到ArkTS主线程处理的任务抛到EventLoop中,等待调度执行。

NAPI_EXTERN napi_status napi_call_threadsafe_function(napi_threadsafe_function func, void* data, napi_threadsafe_function_call_mode is_blocking);
参数说明:
[in] func:线程安全函数对象。
[in] data:上述线程安全回调任务call_js_cb需要处理的数据。
[in] is_blocking:该参数控制接口是否以阻塞的方式运行。如果参数为napi_tsfn_nonblocking,该接口将以非阻塞的方式运行。当缓冲队列已满,调用该接口后,则返回napi_queue_full错误码。如果参数为napi_tsfn_blocking,该接口将以阻塞的方式运行,直到缓冲队列中有可用空间。如果创建线程安全函数时,设置的最大队列容量为0,则napi_call_threadsafe_function()永远不会阻塞。

二、线程安全开发时序交互图

        从上图中,可以看出,当Native线程安全异步接口被调用时,该接口会完成参数解析、数据类型转换、线程安全创建、在创建过程中的注册绑定ArkTS回调处理函数以及创建生产者和消费者线程等。异步任务的调度、执行以及反馈计算结果,均由C++子线程和EventLoop机制进行系统调度完成。

三、线程安全开发步骤(简介)

        

        

        

        

        

四、线程安全开发步骤(实例)   

        1、ArkTS应用侧开发      

// Index.ets文件import testNapi from 'libentry.so';
import Constants from '../../common/constants/CommonConstants';@Entry
@Component
struct Index {@State imagePath: string = Constants.INIT_IMAGE_PATH;imageName: string = '';build() {Column() {...// button list, prompting the user to click the button to select the target image.Column() {...// multi-threads tsf async buttonButton($r('app.string.async_tsf_button_title')).width(Constants.FULL_PARENT).margin($r('app.float.button_common_margin')).onClick(() => {this.imageName = Constants.TSF_BUTTON_IMAGE;testNapi.getImagePathAsyncTSF(this.imageName, (result: string) => {this.imagePath = Constants.IMAGE_ROOT_PATH + result;});})...}...}...}
}

        2、Native侧开发

        导出Native接口:将Native接口导出到ArkTS侧,用于支撑ArkTS对象调用和模块编译构建。

// index.d.ts文件
export const getImagePathAsyncTSF: (imageName: string, callBack: (result: string) => void) => void;

        全局变量定义:定义线程安全函数对象、队列容量、初始化线程数。

// MultiThreads.cpp文件// define global thread safe function
static napi_threadsafe_function tsFun = nullptr;
static constexpr int MAX_MSG_QUEUE_SIZE = 0; // indicates that the queue length is not limited
static constexpr int INITIAL_THREAD_COUNT = 1;

        call_js_cb回调处理定义:定义消费者子线程中,通过napi_call_threadsafe_function抛到ArkTS主线程EventLoop中的回调处理函数。在该函数中,通过napi_call_function调用ArkTS应用侧传入的回调callback,将异步任务搜索到的图片路径结果反馈到ArkTS应用侧。

// MultiThreads.cpp文件static void CallJsFunction(napi_env env, napi_value callBack, [[maybe_unused]] void *context, void *data) {// parse context dataContextData *contextData = static_cast<ContextData *>(data);// define the undefined variable, which is used in napi_call_function// because no other data is transferred, the variable is defined as undefinednapi_value undefined = nullptr;napi_status operStatus = napi_get_undefined(env, &undefined);if (operStatus != napi_ok) {DeleteContext(env, contextData);return;}// convert the calculation result of C++ sub-thread to the napi_value typenapi_value callBackArgs = nullptr;operStatus = napi_create_string_utf8(env, contextData->result.c_str(), contextData->result.length(), &callBackArgs);if (operStatus != napi_ok) {DeleteContext(env, contextData);return;}// call the JS callback and send the async calculation result on the Native to ArkTS applicationnapi_value callBackResult = nullptr;(void)napi_call_function(env, undefined, callBack, 1, &callBackArgs, &callBackResult);// destroy data and release memoryDeleteContext(env, contextData);
}

        Native线程安全函数异步开发接口:解析ArkTS应用侧参数,使用napi_create_threadsafe_function创建线程安全函数对象,并在消费者线程执行函数ConsumeElementTSF中使用napi_call_threadsafe_function将异步回调处理函数call_js_cb抛到EventLoop中,等待调度执行。

// MultiThreads.cpp文件// thread safe function async interface
static napi_value GetImagePathAsyncTSF(napi_env env, napi_callback_info info) {size_t paraNum = 2;napi_value paraArray[2] = {nullptr};// parse parametersnapi_status operStatus = napi_get_cb_info(env, info, &paraNum, paraArray, nullptr, nullptr);if (operStatus != napi_ok) {return nullptr;}napi_valuetype paraDataType = napi_undefined;operStatus = napi_typeof(env, paraArray[0], &paraDataType);if ((operStatus != napi_ok) || (paraDataType != napi_string)) {return nullptr;}operStatus = napi_typeof(env, paraArray[1], &paraDataType);if ((operStatus != napi_ok) || (paraDataType != napi_function)) {return nullptr;}// napi_value convert to char *constexpr size_t buffSize = 100;char strBuff[buffSize]{}; // char buffer for imageName stringsize_t strLength = 0;operStatus = napi_get_value_string_utf8(env, paraArray[0], strBuff, buffSize, &strLength);if ((operStatus != napi_ok) || (strLength == 0)) {return nullptr;}// async resourcenapi_value asyncName = nullptr;string asyncStr = "async napi_threadsafe_function";operStatus = napi_create_string_utf8(env, asyncStr.c_str(), asyncStr.length(), &asyncName);if (operStatus != napi_ok) {return nullptr;}// defines context data. the memory will be released in CompleteFuncauto contextData = new ContextData;contextData->args = strBuff;// create thread safe functionif (tsFun == nullptr) {operStatus =napi_create_threadsafe_function(env, paraArray[1], nullptr, asyncName, MAX_MSG_QUEUE_SIZE,INITIAL_THREAD_COUNT, nullptr, nullptr, nullptr, CallJsFunction, &tsFun);if (operStatus != napi_ok) {DeleteContext(env, contextData);return nullptr;}}// create producer threadthread producer(ProductElement, static_cast<void *>(contextData));producer.detach(); // must be detached// create consumer threadthread consumer(ConsumeElementTSF, static_cast<void *>(contextData));consumer.detach();return nullptr;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1527507.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Linux block_device gendisk和hd_struct到底是个啥关系

本文的源码版本是Linux 5.15版本&#xff0c;有图有真相&#xff1a; 1.先从块设备驱动说起 安卓平台有一个非常典型和重要的块设备驱动&#xff1a;zram&#xff0c;我们来看一下zram这个块设备驱动加载初始化和swapon的逻辑&#xff0c;完整梳理完这个逻辑将对Linux块设备驱…

旅拍景区收银系统+押金原路退回+服装租赁-SAAS本地化及未来之窗行业应用跨平台架构

一、景区旅拍一体化系统 序号系统说明1提成系统用于给照相馆介绍照相拉客的人自动计算提成2押金系统用于服装租赁&#xff08;汉服租赁&#xff09;&#xff0c;设备租赁 &#xff0c;支持押金原路退回3收银系统计算每天收银汇总&#xff0c;月度收银汇总&#xff0c;支出4提成…

云原生之高性能web服务器学习(持续更新中)

高性能web服务器 1 Web服务器的基础介绍1.1 Web服务介绍1.1.1 Apache介绍1.1.2 Nginx-高性能的 Web 服务端 2 Nginx架构与安装2.1 Nginx概述2.1.1 Nginx 功能介绍2.1.2 基础特性2.1.3 Web 服务相关的功能 2.2 Nginx 架构和进程2.2.1 架构2.2.2 Ngnix进程结构 2.3 Nginx 模块介绍…

PyInstaller问题解决 onnxruntime-gpu 使用GPU和CUDA加速模型推理

前言 在模型推理时&#xff0c;需要使用GPU加速&#xff0c;相关的CUDA和CUDNN安装好后&#xff0c;通过onnxruntime-gpu实现。 直接运行python程序是正常使用GPU的&#xff0c;如果使用PyInstaller将.py文件打包为.exe&#xff0c;发现只能使用CPU推理了。 本文分析这个问题…

流媒体与直播的基础理论(其一)

欢迎诸位来阅读在下的博文~ 在这里&#xff0c;在下会不定期发表一些浅薄的知识和经验&#xff0c;望诸位能与在下多多交流&#xff0c;共同努力 文章目录 一、流媒体简介二、流媒体协议常见的流媒体协议 三、视频直播原理与流程通用的视频直播模型视频直播链路 一、流媒体简介…

隐私计算实训营:联邦学习在垂直场景的开发实践

纵向联邦学习 纵向联邦学习的参与方拥有相同样本空间、不同特征空间的数据&#xff0c;通过共有样本数据进行安全联合建模&#xff0c;在金融、广告等领域拥有广泛的应用场景。和横向联邦学习相比&#xff0c;纵向联邦学习的参与方之间需要协同完成数据求交集、模型联合训练和…

Openharmony 下载到rk3568实现横屏

前言&#xff1a; Openharmony 源码版本4.1 release 板子&#xff1a;rk3568 1.修改“abilities”中的“orientation”实现横竖屏 entyr->src->module.json5文件里面添加 "orientation": "landscape", 2.修改系统源码属性实现横竖屏切换 通过这…

以太网--TCP/IP协议(二)

上文中讲述了IP协议&#xff0c;本文主要来讲一下TCP协议。 TCP协议 &#xff08;1&#xff09;端到端通信 直接把源主机应用程序产生的数据传输到目的主机使用这 些数据的应用程序中&#xff0c;就是端到端通信。 &#xff08;2&#xff09;传输层端口 公认端口&#xff0…

ansible--role

简介 roles是ansible&#xff0c;playbooks的目录的组织结构&#xff0c;将代码或文件进行模块化&#xff0c;成为roles的文件目录组织结构。 易读&#xff0c;代码可冲哟美好&#xff0c;层次清晰 目录机构 mkdir roles/nginx/{files,handlers,tasks,templates,vars} -ptou…

Google Play结算防掉单方案

我们公司的产品主要是出海产品,使用的是Google Play支付,但是在上线以后,经常有客诉,说支付以后,权益没有到账,于是对整个Google支付体系做了研究了一下。 我们的整个支付流程图大概如下: 其中后端参考的文档地址为: https://developers.google.com/android-publishe…

GB35114 USC安防平台 中星微国密摄像机配置 流程

中星微国密摄像机配置介绍 如下以中星微VS-IPC8021S-Y-T4摄像机为例&#xff0c;需要先各自获取p10文件&#xff0c;并通过证书签发机构或者测试SM2证书签发获取证书。 网络配置如下: 摄像机的IP地址为192.168.1.108&#xff0c;国标ID为34020000001320000015 系统的IP地址…

C#/.NET/.NET Core推荐学习路线文档文章

前言 专门为C#/.NET/.NET Core推荐学习路线&文档&文章提供的一个Issues&#xff0c;各位小伙伴可以把自己觉得不错的学习路线、文档、文章相关地址分享出来&#x1f91e;。 https://github.com/YSGStudyHards/DotNetGuide/issues/10 &#x1f3f7;️C#/.NET/.NET Cor…

【LVI-SAM】激光雷达点云处理特征提取LIO-SAM 之FeatureExtraction实现细节

激光雷达点云处理特征提取LIO-SAM 之FeatureExtraction实现细节 1. 特征提取实现过程总结1.0 特征提取过程小结1.1 类 FeatureExtraction 的整体结构与作用1.2 详细特征提取的过程1. 平滑度计算&#xff08;calculateSmoothness()&#xff09;2. 标记遮挡点&#xff08;markOcc…

nvm及nodejs安装相关

安装 1.清空文件夹&#xff0c;卸载nvm及nodejs 2.下载安装包 https://github.com/coreybutler/nvm-windows/releases &#xff08;也下载有&#xff09; 3.安装nvm 地址写D:/nvm和D:/nodejs 4.安装nodejs nvm ls available //查询版本 nvm install 16.20.2 //安装对应版…

【H2O2|全栈】关于HTML(1)认识HTML

HTML相关知识 目录 前言 准备工作 WEB前端是什么&#xff1f; HTML是什么&#xff1f; 如何运行HTML文件&#xff1f; 标签 概念 分类 双标签和单标签 行内标签和块标签 HTML文档结构 预告和回顾 UI设计相关 Markdown | Md文档相关 项目合作管理相关 后话 前…

idea快捷键_idea 2024 复制光标所在行 或 复制选择内容,并把复制内容插入光标位置下面 (必备)

Ctrl G 在当前文件跳转到指定行处 Ctrl J 插入自定义动态代码模板 &#xff08;必备&#xff09; Ctrl P 方法参数提示显示 &#xff08;必备&#xff09; Ctrl Q 光标所在的变量 / 类名 / 方法名等上面&#xff08;也可以在提示补充的时候按&#xff09;&#xff0c;显示文…

基于SpringBoot的校园跑腿系统+LW参考示例

系列文章目录 1.基于SSM的洗衣房管理系统原生微信小程序LW参考示例 2.基于SpringBoot的宠物摄影网站管理系统LW参考示例 3.基于SpringBootVue的企业人事管理系统LW参考示例 4.基于SSM的高校实验室管理系统LW参考示例 5.基于SpringBoot的二手数码回收系统原生微信小程序LW参考示…

tabBar设置底部菜单以及选项iconfont图标

1.tabBar设置底部菜单 在官网里面可以了解到tabBar组件的一些知识和注意点&#xff1a; 需要给页面设置一个底部导航的话可以在pages.json里面设置一个tabBar标签&#xff0c;在其里面设置pagePath和text属性。 可以看的pagePath是跳转的地址&#xff0c;text是下面导航的文字…

DataLoader使用

文章目录 一、认识dataloader二、DataLoader整合数据集三、使用DataLoader展示图片方法四、去除结尾不满足batch_size设值图片的展示 一、认识dataloader DataLoader 用于封装数据集&#xff0c;并提供批量加载数据的迭代器。它支持自动打乱数据、多线程数据加载等功能。datas…

SpringDataJPA系列(7)Jackson注解在实体中应用

SpringDataJPA系列(7)Jackson注解在实体中应用 常用的Jackson注解 Springboot中默认集成的是Jackson&#xff0c;我们可以在jackson依赖包下看到Jackson有多个注解 一般常用的有下面这些&#xff1a; 一个实体的示例 测试方法如下&#xff1a; 按照上述图片中的序号做个简…