鸿蒙开发5.0【C++子线程与UI主线程通信方案】

异步流程介绍

ArkTS是单线程的,其通过事件循环机制来处理异步任务,这一特性,同样也深入影响了Node-API的模块开发。在Native线程中既要保证没有多线程问题,又要保证任务的正确执行。

基于threadsafe的实现

方案概述

针对在HarmonyOS中,Native子线程不能直接访问ArkTS主线程的资源的场景,Node-API提供了napi_threadsafe_function这一套线程安全函数接口,用来实现异步通信操作。下面介绍napi_threadsafe_function的方式。

实现流程

  1. 应用侧传入需要执行的异步任务。
  2. Native侧通过napi_create_threadsafe_function创建线程安全函数,将callback注册到线程安全函数中,等待后续其他线程抛异步任务进行回调。
  3. 通过napi_create_async_work,将ExecuteWork与WorkComplete添加为异步任务的执行回调与完成回调。
  4. 通过ExecuteWork函数进行业务处理,并执行线程安全函数,通过WorkComplete函数进行任务执行完成后的资源清理回收工作。
  5. 通过注册给线程安全函数的callback回到主线程,然后通过napi_call_function调用ArkTS函数回到ArkTS侧。
  6. 在ArkTS线程中解析或拒绝promise的唯一方法。

代码实现

C++:

  1. Native侧通过napi_create_threadsafe_function创建线程安全函数,将callback注册到线程安全函数中,等待后续其他线程抛异步任务进行回调。

    struct CallbackData {
    
    napi_threadsafe_function tsfn;
    
    napi_async_work work;
    
    };
    
    
    
    static napi_value StartThread(napi_env env, napi_callback_info info)
    
    {
    
    size_t argc = 1;
    
    napi_value jsCb = nullptr;
    
    CallbackData *callbackData = nullptr;
    
    napi_get_cb_info(env, info, &argc, &jsCb, nullptr, reinterpret_cast<void **>(&callbackData));
    
    
    
    // 创建一个线程安全函数
    
    napi_value resourceName = nullptr;
    
    napi_create_string_utf8(env, "Thread-safe Function Demo", NAPI_AUTO_LENGTH, &resourceName);
    
    napi_create_threadsafe_function(env, jsCb, nullptr, resourceName, 0, 1, callbackData, nullptr,
    
    callbackData, CallJs, &callbackData->tsfn);
    
    
    
    // 创建一个异步任务
    
    napi_create_async_work(env, nullptr, resourceName, ExecuteWork, WorkComplete, callbackData,
    
    &callbackData->work);
    
    
    
    // 将异步任务加入到异步队列中
    
    napi_queue_async_work(env, callbackData->work);
    
    return nullptr;
    
    }
    
  2. 通过ExecuteWork函数进行业务处理,并执行线程安全函数,通过WorkComplete函数进行任务执行完成后的资源清理回收工作。

    static void ExecuteWork(napi_env env, void *data) {
    
    CallbackData_ThreadSafe *callbackData = reinterpret_cast<CallbackData_ThreadSafe *>(data);
    
    std::promise<std::string> promise;
    
    auto future = promise.get_future();
    
    napi_call_threadsafe_function(callbackData->tsfn, &promise, napi_tsfn_nonblocking);
    
    try {
    
    auto result = future.get();
    
    OH_LOG_INFO(LOG_APP, "XXX, Result from JS %{public}s", result.c_str());
    
    } catch (const std::exception &e) {
    
    OH_LOG_INFO(LOG_APP, "XXX, Result from JS %{public}s", e.what());
    
    }
    
    }
    
    
    
    static void WorkComplete(napi_env env, napi_status status, void *data) {
    
    CallbackData_ThreadSafe *callbackData = reinterpret_cast<CallbackData_ThreadSafe *>(data);
    
    napi_release_threadsafe_function(callbackData->tsfn, napi_tsfn_release);
    
    napi_delete_async_work(env, callbackData->work);
    
    callbackData->tsfn = nullptr;
    
    callbackData->work = nullptr;
    
    }
    
  3. 通过注册给线程安全函数的callback回到主线程,然后通过napi_call_function调用ArkTS 函数回到ArkTS侧。

    static void CallJs(napi_env env, napi_value jsCb, void *context, void *data) {
    
    if (env == nullptr) {
    
    return;
    
    }
    
    napi_value undefined = nullptr;
    
    napi_value promise = nullptr;
    
    napi_get_undefined(env, &undefined);
    
    napi_call_function(env, undefined, jsCb, 0, nullptr, &promise);
    
    napi_value thenFunc = nullptr;
    
    if (napi_get_named_property(env, promise, "then", &thenFunc) != napi_ok) {
    
    return;
    
    }
    
    napi_value resolvedCallback;
    
    napi_value rejectedCallback;
    
    napi_create_function(env, "resolvedCallback", NAPI_AUTO_LENGTH, ResolvedCallback, data, &resolvedCallback);
    
    napi_create_function(env, "rejectedCallback", NAPI_AUTO_LENGTH, RejectedCallback, data, &rejectedCallback);
    
    napi_value argv[2] = {resolvedCallback, rejectedCallback};
    
    napi_call_function(env, promise, thenFunc, 2, argv, nullptr);
    
    }
    
  4. 在ArkTS线程中解析或拒绝promise。

    static napi_value ResolvedCallback(napi_env env, napi_callback_info info) {
    
    void *data = nullptr;
    
    size_t argc = 1;
    
    napi_value argv[1];
    
    if (napi_get_cb_info(env, info, &argc, argv, nullptr, &data) != napi_ok) {
    
    return nullptr;
    
    }
    
    size_t result = 0;
    
    char buf[32] = {0};
    
    napi_get_value_string_utf8(env, argv[0], buf, 32, &result);
    
    reinterpret_cast<std::promise<std::string> *>(data)->set_value(std::string(buf));
    
    return nullptr;
    
    }
    
    
    
    static napi_value RejectedCallback(napi_env env, napi_callback_info info) {
    
    void *data = nullptr;
    
    if (napi_get_cb_info(env, info, nullptr, nullptr, nullptr, &data) != napi_ok) {
    
    return nullptr;
    
    }
    
    reinterpret_cast<std::promise<std::string> *>(data)->set_exception(
    
    std::make_exception_ptr(std::runtime_error("Error in jsCallback")));
    
    return nullptr;
    
    }
    

TS:

import nativeModule from 'libentry.so';



// 应用侧传入需要执行的异步任务

let callback = (): Promise<string> => {

return new Promise((resolve) => {

setTimeout(() => {

resolve("string from promise");

}, 5000);

});

}

nativeModule.startThread(callback);

以上就是本篇文章所带来的鸿蒙开发中一小部分技术讲解;想要学习完整的鸿蒙全栈技术。可以在结尾找我可全部拿到!
下面是鸿蒙的完整学习路线,展示如下:
1

除此之外,根据这个学习鸿蒙全栈学习路线,也附带一整套完整的学习【文档+视频】,内容包含如下

内容包含了:(ArkTS、ArkUI、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、鸿蒙南向开发、鸿蒙项目实战)等技术知识点。帮助大家在学习鸿蒙路上快速成长!

鸿蒙【北向应用开发+南向系统层开发】文档

鸿蒙【基础+实战项目】视频

鸿蒙面经

2

为了避免大家在学习过程中产生更多的时间成本,对比我把以上内容全部放在了↓↓↓想要的可以自拿喔!谢谢大家观看!
3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值