请参考使用Node-API接口进行线程安全开发:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/use-napi-thread-safety-0000001774280466简单的DEMO示例参考如下:index.d.ts文件:export const jsRegister: (func: (data:number) => number) => void; export const serviceNotifyFun: (data:number, type:number) => void; Index.ets文件: import { hilog } from '@kit.PerformanceAnalysisKit'; import testNapi from 'libentry.so'; @Entry @Component struct Index { @State message: string = 'Hello World'; build() { Row() { Column() { Button("注册") .onClick(() => { testNapi.jsRegister((value: number) => { hilog.info(0x0000, 'testTag', 'js callback value:%{public}d', value); return (value + 11); }) }).margin(10) Button("业务通知") .onClick(() => { for (let i:number = 0; i < 10; i++) { testNapi.serviceNotifyFun(i + 22, i + 55); } }).margin(10) } .width('100%') } .height('100%') } }napi\_init.cpp文件:#include "napi/native_api.h" #define LOG_TAG "testTag" #include "hilog/log.h" #include <pthread.h> pthread_mutex_t mutex_ = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond_ = PTHREAD_COND_INITIALIZER; // 指向napi_value js_cb napi_ref cbObj = nullptr; // 线程安全函数 napi_threadsafe_function tsfn; static int cValue = 999; typedef struct TestData { int data; int type; } TestData; struct lnode { TestData data; struct lnode *next; }; struct linkQueue { lnode *head; lnode *tail; int count; }; struct linkQueue g_Queue; static void InitQueue() { g_Queue.head = nullptr; g_Queue.tail = nullptr; g_Queue.count = 0; } static bool Push(TestData &data) { lnode *node = new lnode(); if (node == nullptr) { return false; } node->next = nullptr; node->data = data; if (g_Queue.count == 0) { g_Queue.head = node; g_Queue.tail = node; } else { g_Queue.tail->next = node; g_Queue.tail = node; } g_Queue.count++; return true; } static TestData *Pop() { if (g_Queue.count == 0) { return nullptr; } lnode *node = g_Queue.head; g_Queue.count--; g_Queue.head = g_Queue.head->next; TestData *data = new TestData(); if (data == nullptr) { delete node; return nullptr; } *data = node->data; delete node; return data; } bool IsEmpty() { return g_Queue.count == 0; } static napi_value ServiceNotifyFun(napi_env env, napi_callback_info info) { if (cbObj == nullptr) { OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG, "cbObj == nullptr"); return nullptr; } size_t argc = 2; napi_value args[2] = {nullptr}; napi_value ets_fun; napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); TestData testData; napi_get_value_int32(env, args[0], &testData.data); napi_get_value_int32(env, args[1], &testData.type); OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG, "ServiceNotifyFun:%{public}d,type:%{public}d", testData.data, testData.type); pthread_mutex_lock(&mutex_); Push(testData); pthread_mutex_unlock(&mutex_); pthread_cond_signal(&cond_); return nullptr; } // 回调 static void CallJs(napi_env env, napi_value js_cb, void *context, void *data) { TestData *testDatal = (TestData *)data; OH_LOG_INFO(LOG_APP, "CallJs, data=%{public}d, type:%{public}d", testDatal->data, testDatal->type); delete testDatal; OH_LOG_Print(LOG_APP, LOG_WARN, LOG_DOMAIN, "testTag", "enter CallJs"); // 获取引用值 napi_get_reference_value(env, cbObj, &js_cb); // 创建一个ArkTS number作为ArkTS function的入参。 napi_value argv; napi_create_int32(env, cValue, &argv); napi_value result = nullptr; napi_call_function(env, nullptr, js_cb, 1, &argv, &result); napi_get_value_int32(env, result, &cValue); OH_LOG_Print(LOG_APP, LOG_WARN, LOG_DOMAIN, "testTag", "end CallJs, result:%{public}d", cValue); } static void *ServiceHandle(void *args) { OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG, "start thread_call"); pthread_detach(pthread_self()); TestData *testData = nullptr; while (true) { pthread_mutex_lock(&mutex_); pthread_cond_wait(&cond_, &mutex_); while (!IsEmpty()) { testData = Pop(); if (testData == nullptr) { break; } OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG, "service Handle"); napi_acquire_threadsafe_function(tsfn); napi_call_threadsafe_function(tsfn, testData, napi_tsfn_blocking); testData = nullptr; } pthread_mutex_unlock(&mutex_); } OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG, "end thread_call"); return nullptr; } static napi_value JsRegister(napi_env env, napi_callback_info info) { OH_LOG_INFO(LOG_APP, "start JsRegister"); // 从ArkTS侧获取的参数的数量 size_t argc = 1; napi_value js_cb, work_name; // 获取ArkTS参数 napi_get_cb_info(env, info, &argc, &js_cb, nullptr, nullptr); // 指向napi_value js_cb 的 napi_ref cbObj napi_create_reference(env, js_cb, 1, &cbObj); // 通过UTF8编码的C字符串数据创建work_name napi_create_string_utf8(env, "Work Item", NAPI_AUTO_LENGTH, &work_name); // 创建线程安全函数 napi_create_threadsafe_function(env, js_cb, NULL, work_name, 0, 1, NULL, NULL, NULL, CallJs, &tsfn); OH_LOG_INFO(LOG_APP, "end JsRegister"); return nullptr; } EXTERN_C_START static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor desc[] = { { "jsRegister", nullptr, JsRegister, nullptr, nullptr, nullptr, napi_default, nullptr }, { "serviceNotifyFun", nullptr, ServiceNotifyFun, nullptr, nullptr, nullptr, napi_default, nullptr } }; napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); InitQueue(); pthread_t tid; pthread_create(&tid, NULL, &ServiceHandle, NULL); return exports; } EXTERN_C_END static napi_module demoModule = { .nm_version = 1, .nm_flags = 0, .nm_filename = nullptr, .nm_register_func = Init, .nm_modname = "entry", .nm_priv = ((void*)0), .reserved = { 0 }, }; extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }CMakeLists.txt文件:# the minimum version of CMake. cmake_minimum_required(VERSION 3.4.1) project(napi_call_threadsafe_function) set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) if(DEFINED PACKAGE_FIND_FILE) include(${PACKAGE_FIND_FILE}) endif() include_directories(${NATIVERENDER_ROOT_PATH} ${NATIVERENDER_ROOT_PATH}/include) add_library(entry SHARED napi_init.cpp) target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so)
请参考使用Node-API接口进行线程安全开发:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/use-napi-thread-safety-0000001774280466
简单的DEMO示例参考如下:
index.d.ts文件:
napi\_init.cpp文件:
CMakeLists.txt文件: