OpenHarmony开发者论坛

标题: Napi线程安全函数使用示例 [打印本页]

作者: 深开鸿_苟晶晶    时间: 昨天 17:17
标题: Napi线程安全函数使用示例
[md]## 简介

napi如何使用线程安全函数。

## 文档环境

开发环境:Windows 10

DevEco Studio 版本:DevEco Studio 4.1 Release(4.1.0.400)

SDK 版本:API version 11 (4.1.7.5 Release)

开发板型号:DAYU200(RK3568)

OpenHarmony版本:OpenHarmony 5.0.2.51

## 使用示例

1. 接口声明、编译配置、模块注册
   接口声明
   
   ```
   export function startThreadsafefunc(callback: Callback<string>):void
   ```
   
   编译配置
   
   ```
   cmake_minimum_required(VERSION 3.4.1)
   project(MyApplication2)
   
   set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
   
   include_directories(${NATIVERENDER_ROOT_PATH}
                       ${NATIVERENDER_ROOT_PATH}/include)
   
   add_library(entry SHARED threadsafe4.cpp)
   target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so)
   ```
   
   模块注册
   
   ```
   EXTERN_C_START
   static napi_value Init(napi_env env, napi_value exports) {
       // Define properties and methods for a N-API object.
       napi_property_descriptor desc[] = {
           {"startThreadsafefunc", nullptr, StartThreadsafefunc, nullptr, nullptr, nullptr, napi_default, nullptr}
       };
       // Add an array of properties to a ArkTs object.
       napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
       return exports;
   }
   EXTERN_C_END
   
   static napi_module nativeModule = {
       .nm_version = 1,
       .nm_flags = 0,
       .nm_filename = nullptr,
       .nm_register_func = Init,
       .nm_modname = "entry",
       .nm_priv = nullptr,
       .reserved = { 0 },
   };
   
   extern "C" __attribute__((constructor)) void RegisterObjectWrapModule()
   {
       napi_module_register(&nativeModule);
   }
   ```
2. 创建线程安全函数,
   
   ```
   struct MyContext {
       std::string importantString;
   };
   // Thread-safe JavaScript function object.
   napi_threadsafe_function g_threadsafeFunction;
   static void CallbackFunction(napi_env env, napi_value jsCallback, void *context, void *data)
   {
       size_t argc = 1;
       napi_value argv[1];
       int* aa = static_cast<int*>(data);
       OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "THREAD SAFE", "Native CallbackFunction *data: %{public}d", *aa);
       MyContext* myContext = static_cast<MyContext*>(context);
       napi_create_string_utf8(env, myContext->importantString.c_str(), NAPI_AUTO_LENGTH, &argv[0]);
       // Execute the callback function in a JavaScript environment. After the data is callbacked to JS, it will not wait for JS to finish executing.
       napi_call_function(env, nullptr, jsCallback, argc, argv, nullptr);
   }
   static void FinalizeFunction(napi_env env, void* data, void* hint)
   {
       OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "THREAD SAFE", "Native FinalizeFunction called.");
       MyContext* myContext = static_cast<MyContext*>(data);
       delete myContext;
   }
   static void ThreadFunction(void *data)
   {
       // Asynchronously call a JavaScript function in another thread.
       std::this_thread::sleep_for(std::chrono::seconds(1));
       OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "THREAD SAFE", "Native another thread sleep 1s.");
       // Invoke a JavaScript function asynchronously from a native thread. After this, it will execute CallbackFunction to callback data to js.
       int *param = new int(10);
       napi_call_threadsafe_function(g_threadsafeFunction, param, napi_tsfn_nonblocking);
       //  Decrement the reference count of a threadsafe function, potentially destroying it. After this, it will execute FinalizeFunction to release data.
       napi_release_threadsafe_function(g_threadsafeFunction, napi_tsfn_release);
   }
   napi_value StartThreadsafefunc(napi_env env, napi_callback_info info)
   {
       size_t argc = 1;
       napi_value args[1];
       napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
       MyContext* context = new MyContext{"Hello from C++"};
       napi_value name;
       napi_create_string_utf8(env, "testThreadsafefunc", NAPI_AUTO_LENGTH, &name);
       // Create a thread-safe function that can be called from worker threads.
       napi_create_threadsafe_function(env, args[0], nullptr, name, 0, 1,
           context, FinalizeFunction, context, CallbackFunction, &g_threadsafeFunction);
       // Start a new thread.
       std::thread newThread(ThreadFunction, nullptr);
       newThread.join();
       OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "THREAD SAFE", "Native main thread.");
       return nullptr;
   }
   ```
   
   调用流程:
   
   (1) 调用napi\_create\_threadsafe\_function方法:注入线程安全的方法CallbackFunction,该方法按照nodejs文档要求的方法签名,定义为static void CallbackFunction(napi\_env env, napi\_value js\_callback, void \*context, void \*data);第三个参数 \*context 为创建该函数时传递的值,第四个参数 \*data 为调用该函数的地方的自定义数据,然后将创建的CallbackFunction方法绑定到napi\_threadsafe\_function  g\_threadsafeFunction上。注入FinalizeFunction方法用于资源的清理,该方法按照nodejs文档要求的方法签名,定义为static void FinalizeFunction(napi\_env env, void \*data, void \*hint );第二个参数 \*data即为传递的需要释放的数据。
   
   (2) 新开一个线程B,在B线程中调用napi\_call\_threadsafe\_function(g\_threadsafeFunction, param, napi\_tsfn\_nonblocking); 其中param参数就是植入自定义数据的地方。主线程的CallbackFunction被napi主动调用,第四个参数 \*data就是第三步的param;第三个参数 \*context即为napi\_create\_threadsafe\_function接口倒数第三个参数传递的值;在CallbackFunction可以对数据进行打印或者将数据回调到js层。
   
   (3) 在B线程中调用napi\_release\_threadsafe\_function(g\_threadsafeFunction, napi\_tsfn\_release);用于销毁线程安全函数,主线程的FinalizeFunction被napi主动调用进行资源的清理。
3. ArkTS侧示例代码
   
   ```
   testNapi.startThreadsafefunc((res: string) => {
       console.log('THREAD SAFE console callback res is :', res);
   })
   ```
4. 运行后,执行结果如下:
   
   ```
   A00000/THREAD SAFE             com.examp...lication  I     Native another thread sleep 1s.
   A00000/THREAD SAFE             com.examp...lication  I     Native main thread.
   A00000/THREAD SAFE             com.examp...lication  I     Native CallbackFunction *data: 10
   A03d00/JSAPP                   com.examp...lication  I     THREAD SAFE js callback res is : Hello from C++
   A00000/THREAD SAFE             com.examp...lication  I     Native FinalizeFunction called.
   ```

[/md]




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