文档管理中心
指南应用框架ArkTS(方舟编程语言)ArkTS并发应用多线程开发实践应用多线程开发实践案例自定义Native Sendable对象的多线程操作场景

自定义Native Sendable对象的多线程操作场景

ArkTS支持开发者自定义Native Sendable对象,Sendable对象提供了并发实例间高效的通信能力,即引用传递,适用于开发者自定义大对象需要线程间通信的场景,例如子线程读取数据库数据并返回给宿主线程。

本示例将详细说明如何使用自定义Native Sendable对象实现并发实例间数据共享。

  1. 接口声明中自定义Sendable类。

    收起
    自动换行
    深色代码主题
    复制
    1. // Index.d.ets
    2. @Sendable
    3. export class MyObject {
    4. constructor(arg: number);
    5. plusOne(): number;
    6. public get value(): number;
    7. public set value(newVal: number);
    8. }
  2. 编译配置。

    收起
    自动换行
    深色代码主题
    复制
    1. # CMakeLists.txt
    2. # the minimum version of CMake.
    3. cmake_minimum_required(VERSION 3.5.0)
    4. project(napi_wrap_sendable_demo)
    5. set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
    6. if(DEFINED PACKAGE_FIND_FILE)
    7. include(${PACKAGE_FIND_FILE})
    8. endif()
    9. include_directories(${NATIVERENDER_ROOT_PATH}
    10. ${NATIVERENDER_ROOT_PATH}/include)
    11. add_definitions("-DLOG_DOMAIN=0x0000")
    12. add_definitions("-DLOG_TAG=\"testTag\"")
    13. add_library(entry SHARED napi_init.cpp)
    14. target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so)

    修改与Index.d.ets同目录下的配置文件oh-package.json5,配置如下:

    收起
    自动换行
    深色代码主题
    复制
    1. {
    2. "name": "libentry.so",
    3. "types": "./Index.d.ets",
    4. "version": "1.0.0",
    5. "description": "Please describe the basic information."
    6. }
  3. Native实现各项接口功能,例如取值、设置值或者给Native对象的值加1等功能。

    收起
    自动换行
    深色代码主题
    复制
    1. // napi_init.cpp
    2. #include "napi/native_api.h"
    3. #include "hilog/log.h"
    4. // 一个native类,它的实例在下面会包装在ArkTS的Sendable对象中
    5. class MyObject {
    6. public:
    7. static napi_value Init(napi_env env, napi_value exports);
    8. static void Destructor(napi_env env, void *nativeObject, void *finalizeHint);
    9. private:
    10. explicit MyObject(double value = 0);
    11. ~MyObject();
    12. static napi_value New(napi_env env, napi_callback_info info);
    13. static napi_value GetValue(napi_env env, napi_callback_info info);
    14. static napi_value SetValue(napi_env env, napi_callback_info info);
    15. static napi_value PlusOne(napi_env env, napi_callback_info info);
    16. double value_;
    17. napi_env env_;
    18. };
    19. static thread_local napi_ref g_ref = nullptr;
    20. MyObject::MyObject(double value) : value_(value), env_(nullptr) {}
    21. MyObject::~MyObject() {}
    22. void MyObject::Destructor(napi_env env, void *nativeObject, [[maybe_unused]] void *finalizeHint)
    23. {
    24. OH_LOG_INFO(LOG_APP, "MyObject::Destructor called");
    25. reinterpret_cast<MyObject *>(nativeObject)->~MyObject();
    26. }
    27. // 在构造函数中绑定ArkTS Sendable对象与C++对象
    28. napi_value MyObject::New(napi_env env, napi_callback_info info)
    29. {
    30. OH_LOG_INFO(LOG_APP, "MyObject::New called");
    31. napi_value newTarget;
    32. napi_get_new_target(env, info, &newTarget);
    33. if (newTarget != nullptr) {
    34. // 使用`new MyObject(...)`调用方式
    35. size_t argc = 1;
    36. napi_value args[1];
    37. napi_value jsThis;
    38. napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr);
    39. double value = 0.0;
    40. napi_valuetype valuetype;
    41. napi_typeof(env, args[0], &valuetype);
    42. if (valuetype != napi_undefined) {
    43. napi_get_value_double(env, args[0], &value);
    44. }
    45. MyObject *obj = new MyObject(value);
    46. obj->env_ = env;
    47. // 通过napi_wrap_sendable将ArkTS Sendable对象jsThis与C++对象obj绑定
    48. napi_wrap_sendable(env, jsThis, reinterpret_cast<void *>(obj), MyObject::Destructor, nullptr);
    49. return jsThis;
    50. } else {
    51. // 使用`MyObject(...)`调用方式
    52. size_t argc = 1;
    53. napi_value args[1];
    54. napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    55. napi_value cons;
    56. napi_get_reference_value(env, g_ref, &cons);
    57. napi_value instance;
    58. napi_new_instance(env, cons, argc, args, &instance);
    59. return instance;
    60. }
    61. }
    62. // 取出Native对象的值
    63. napi_value MyObject::GetValue(napi_env env, napi_callback_info info)
    64. {
    65. OH_LOG_INFO(LOG_APP, "MyObject::GetValue called");
    66. napi_value jsThis;
    67. napi_get_cb_info(env, info, nullptr, nullptr, &jsThis, nullptr);
    68. MyObject *obj;
    69. // 通过napi_unwrap_sendable将jsThis之前绑定的C++对象取出,并对其进行操作
    70. napi_unwrap_sendable(env, jsThis, reinterpret_cast<void **>(&obj));
    71. napi_value num;
    72. napi_create_double(env, obj->value_, &num);
    73. return num;
    74. }
    75. // 设置Native对象的值
    76. napi_value MyObject::SetValue(napi_env env, napi_callback_info info)
    77. {
    78. OH_LOG_INFO(LOG_APP, "MyObject::SetValue called");
    79. size_t argc = 1;
    80. napi_value value;
    81. napi_value jsThis;
    82. napi_get_cb_info(env, info, &argc, &value, &jsThis, nullptr);
    83. MyObject *obj;
    84. // 通过napi_unwrap_sendable将jsThis之前绑定的C++对象取出,并对其进行操作
    85. napi_unwrap_sendable(env, jsThis, reinterpret_cast<void **>(&obj));
    86. napi_get_value_double(env, value, &obj->value_);
    87. return nullptr;
    88. }
    89. // 给Native对象的值加1
    90. napi_value MyObject::PlusOne(napi_env env, napi_callback_info info)
    91. {
    92. OH_LOG_INFO(LOG_APP, "MyObject::PlusOne called");
    93. napi_value jsThis;
    94. napi_get_cb_info(env, info, nullptr, nullptr, &jsThis, nullptr);
    95. MyObject *obj;
    96. // 通过napi_unwrap_sendable将jsThis之前绑定的C++对象取出,并对其进行操作
    97. napi_unwrap_sendable(env, jsThis, reinterpret_cast<void **>(&obj));
    98. obj->value_ += 1;
    99. napi_value num;
    100. napi_create_double(env, obj->value_, &num);
    101. return num;
    102. }
    103. napi_value MyObject::Init(napi_env env, napi_value exports)
    104. {
    105. napi_value num;
    106. napi_create_double(env, 0, &num);
    107. napi_property_descriptor properties[] = {
    108. {"value", nullptr, nullptr, GetValue, SetValue, nullptr, napi_default, nullptr},
    109. {"plusOne", nullptr, PlusOne, nullptr, nullptr, nullptr, napi_default, nullptr},
    110. };
    111. napi_value cons;
    112. // 定义一个Sendable class MyObject
    113. napi_define_sendable_class(env, "MyObject", NAPI_AUTO_LENGTH, New, nullptr,
    114. sizeof(properties) / sizeof(properties[0]), properties, nullptr, &cons);
    115. // &g_ref与模块同生命周期
    116. napi_create_reference(env, cons, 1, &g_ref);
    117. // 在exports对象上挂载MyObject类
    118. napi_set_named_property(env, exports, "MyObject", cons);
    119. return exports;
    120. }
    121. EXTERN_C_START
    122. // 模块初始化
    123. static napi_value Init(napi_env env, napi_value exports)
    124. {
    125. MyObject::Init(env, exports);
    126. return exports;
    127. }
    128. EXTERN_C_END
    129. // 准备模块加载相关信息,将上述Init函数与本模块名等信息记录下来
    130. static napi_module nativeModule = {
    131. .nm_version = 1,
    132. .nm_flags = 0,
    133. .nm_filename = nullptr,
    134. .nm_register_func = Init,
    135. .nm_modname = "entry",
    136. .nm_priv = nullptr,
    137. .reserved = {0},
    138. };
    139. // 加载so时,自动调用该函数,将上述nativeModule模块注册到系统中
    140. extern "C" __attribute__((constructor)) void RegisterObjectWrapModule() { napi_module_register(&nativeModule); }
  4. ArkTS侧在UI主线程中定义Sendable实例对象并传递给TaskPool子线程,子线程处理完数据后返回UI主线程,UI主线程可以继续访问该Sendable实例对象。

    收起
    自动换行
    深色代码主题
    复制
    1. // Index.ets
    2. import { MyObject } from 'libentry.so';
    3. import { taskpool } from '@kit.ArkTS';
    4. @Concurrent
    5. async function sum(object: MyObject) {
    6. object.value = 2000;
    7. let num = object.plusOne();
    8. console.info('taskpool thread num is ' + num); // 日志输出:taskpool thread num is 2001
    9. return num;
    10. }
    11. @Entry
    12. @Component
    13. struct Index {
    14. @State message: string = '使用Sendable对象进行线程间通信';
    15. build() {
    16. Row() {
    17. Column() {
    18. Button(this.message)
    19. .fontSize($r('app.float.page_text_font_size'))
    20. .fontWeight(FontWeight.Bold)
    21. .onClick(async () => {
    22. let object: MyObject = new MyObject(0);
    23. object.value = 1023;
    24. let num = object.plusOne();
    25. console.info('host thread num1 is ' + num); // 日志输出:host thread num1 is 1024
    26. let task = new taskpool.Task(sum, object);
    27. let result = await taskpool.execute(task);
    28. console.info('host thread result is ' + result); // 日志输出:host thread result is 2001
    29. console.info('host thread num2 is ' + object.value); // 日志输出:host thread num2 is 2001
    30. this.message = 'host thread num2 is ' + object.value;
    31. })
    32. }
    33. .width('100%')
    34. }
    35. .height('100%')
    36. }
    37. }
在 指南 中进行搜索
请输入您想要搜索的关键词