1# C++线程间数据共享场景 2<!--Kit: ArkTS--> 3<!--Subsystem: CommonLibrary--> 4<!--Owner: @lijiamin2025--> 5<!--Designer: @weng-changcheng--> 6<!--Tester: @kirl75; @zsw_zhushiwei--> 7<!--Adviser: @ge-yafang--> 8 9在C++层进行多线程并发计算时,需要在每个C++线程上创建ArkTS执行环境,直接调用API。这样可以避免在非UI主线程回调时等待UI主线程的API调用结果。同时,还需要在C++线程之间共享和操作Sendable对象。 10 11为了支持此类场景,C++线程需要能够创建并调用ArkTS,同时支持对Sendable对象进行多线程共享和操作。 12 13 14## 在C++线程上调用ArkTS能力 15 16使用Node-API接口在C++线程中创建ArkTS运行环境并调用的方法,可以参考[使用Node-API接口创建ArkTS运行时环境](../napi/use-napi-ark-runtime.md)。 17 18核心代码片段如下所示: 19 20ArkTS文件定义。 21 22```ts 23// SendableObjTest.ets 24@Sendable 25export class SendableObjTest { 26 static newSendable() { 27 return 1024; 28 } 29} 30``` 31<!-- @[arkts_define_obj](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkTS/ArkTsConcurrent/ApplicationMultithreadingDevelopment/NativeInterthreadShared/entry/src/main/ets/pages/SendableObjTest.ets) --> 32 33 34实现Native加载ArkTS模块的能力。 35 36```cpp 37// napi_init.cpp 38#include "napi/native_api.h" 39#include <thread> 40static void *CreateArkRuntimeFunc(void *arg) 41{ 42 // 1. 创建基础运行环境 43 napi_env env = nullptr; 44 napi_status ret = napi_create_ark_runtime(&env); 45 if (ret != napi_ok) { 46 std::abort(); 47 } 48 // 2. 加载自定义模块,假定SendableObjTest中提供创建sendable对象的方法newSendable 49 napi_value test = nullptr; 50 ret = napi_load_module_with_info(env, "entry/src/main/ets/pages/SendableObjTest", "com.example.myapplication/entry", &test); 51 if (ret != napi_ok) { 52 std::abort(); 53 } 54 napi_value sendableObjTest = nullptr; 55 ret = napi_get_named_property(env, test, "SendableObjTest", &sendableObjTest); 56 if (ret != napi_ok) { 57 std::abort(); 58 } 59 // 3. 使用ArkTS中的newSendable,假设sendableObjTest中有一个函数newSendable能返回sendable对象 60 napi_value newSendable = nullptr; 61 ret = napi_get_named_property(env, sendableObjTest, "newSendable", &newSendable); 62 if (ret != napi_ok) { 63 std::abort(); 64 } 65 // 4. 调用newSendable函数返回新创建的sendable对象,并保存在result中 66 napi_value result = nullptr; 67 ret = napi_call_function(env, sendableObjTest, newSendable, 0, nullptr, &result); 68 if (ret != napi_ok) { 69 std::abort(); 70 } 71 // 5. 获取ArkTS返回的结果 72 int value0; 73 napi_get_value_int32(env, result, &value0); 74 if (value0 != 1024) { 75 std::abort(); 76 } 77 // 6. 销毁ArkTS环境 78 ret = napi_destroy_ark_runtime(&env); 79 return nullptr; 80} 81``` 82<!-- @[native_load_arkts_module](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkTS/ArkTsConcurrent/ApplicationMultithreadingDevelopment/NativeInterthreadShared/entry/src/main/cpp/napi_init.cpp) --> 83 84主要步骤包括:创建执行环境、加载模块、查找并调用模块函数(或直接通过Node-API接口创建Sendable对象),最后销毁执行环境。加载模块的详细信息,请参见[使用Node-API接口进行模块加载](../napi/use-napi-load-module-with-info.md)。查找并调用函数及更多Node-API接口能力,请参见[Node-API](../reference/native-lib/napi.md)。 85 86## 在C++线程之间操作Sendable共享对象 87 88在C++中调用ArkTS能力后,需要通过序列化和反序列化跨线程传递。napi_value不是多线程安全的,不能直接在多线程之间操作和共享。 89 90下面代码例子说明了如何序列化和反序列化传递对象,注意因为Sendable共享对象是引用传递,所以序列化不会产生另外一份拷贝数据,而是直接传递对象引用到反序列化线程,所以在性能上相比非Sendable对象的序列化和反序列化更为高效。 91 92ArkTS文件定义。 93 94```ts 95// SendableObjTest.ets 96@Sendable 97export class SendableObjTest { 98 static newSendable() { 99 return 1024; 100 } 101} 102``` 103<!-- @[arkts_define_obj](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkTS/ArkTsConcurrent/ApplicationMultithreadingDevelopment/NativeInterthreadShared/entry/src/main/ets/pages/SendableObjTest.ets) --> 104 105在Native中实现两个线程的序列化和反序列化Sendable的逻辑。 106 107```cpp 108// napi_init.cpp 109#include "napi/native_api.h" 110#include <thread> 111 112static void *serializationData = nullptr; 113static void *CreateEnvAndSendSendable(void *) { 114 // 1. 创建基础运行环境 115 napi_env env = nullptr; 116 napi_status ret = napi_create_ark_runtime(&env); 117 if (ret != napi_ok) { 118 std::abort(); 119 } 120 // 2. 加载自定义模块,假定SendableObjTest中提供创建sendable对象的方法newSendable 121 napi_value test = nullptr; 122 ret = napi_load_module_with_info(env, "entry/src/main/ets/pages/SendableObjTest", "com.example.myapplication/entry", 123 &test); 124 if (ret != napi_ok) { 125 std::abort(); 126 } 127 napi_value sendableObjTest = nullptr; 128 ret = napi_get_named_property(env, test, "SendableObjTest", &sendableObjTest); 129 if (ret != napi_ok) { 130 std::abort(); 131 } 132 // 3. 使用ArkTS中的newSendable,假设sendableObjTest中有一个函数newSendable能返回sendable对象 133 napi_value newSendable = nullptr; 134 ret = napi_get_named_property(env, sendableObjTest, "newSendable", &newSendable); 135 if (ret != napi_ok) { 136 std::abort(); 137 } 138 // 4. 调用newSendable函数返回新创建的sendable对象,并保存在result中 139 napi_value result = nullptr; 140 ret = napi_call_function(env, sendableObjTest, newSendable, 0, nullptr, &result); 141 if (ret != napi_ok) { 142 std::abort(); 143 } 144 // 5. 序列化sendable对象 145 napi_value undefined; 146 napi_get_undefined(env, &undefined); 147 ret = napi_serialize(env, result, undefined, undefined, &serializationData); 148 if (ret != napi_ok) { 149 std::abort(); 150 } 151 return nullptr; 152} 153 154static void *CreateEnvAndReceiveSendable(void *) { 155 // 1. 创建基础运行环境 156 napi_env env = nullptr; 157 napi_status ret = napi_create_ark_runtime(&env); 158 if (ret != napi_ok) { 159 std::abort(); 160 } 161 // 2. 反序列化获取sendable共享对象,结果保存在result中,这个result就可以通过napi接口进行各种操作了 162 napi_value result = nullptr; 163 ret = napi_deserialize(env, serializationData, &result); 164 if (ret != napi_ok) { 165 std::abort(); 166 } 167 // 3. 删除序列化数据 168 ret = napi_delete_serialization_data(env, serializationData); 169 if (ret != napi_ok) { 170 std::abort(); 171 } 172 napi_valuetype valuetype0; 173 napi_typeof(env, result, &valuetype0); 174 if (valuetype0 != napi_number) { 175 std::abort(); 176 } 177 int value0; 178 napi_get_value_int32(env, result, &value0); 179 if (value0 != 1024) { 180 std::abort(); 181 } 182 return nullptr; 183} 184 185static napi_value TestSendSendable([[maybe_unused]] napi_env env, [[maybe_unused]] napi_callback_info info) { 186 std::thread t1(CreateEnvAndSendSendable, nullptr); 187 t1.join(); 188 std::thread t2(CreateEnvAndReceiveSendable, nullptr); 189 t2.join(); 190 return nullptr; 191} 192 193EXTERN_C_START 194static napi_value Init(napi_env env, napi_value exports) { 195 napi_property_descriptor desc[] = { 196 {"testSendSendable", nullptr, TestSendSendable, nullptr, nullptr, nullptr, napi_default, nullptr}}; 197 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); 198 return exports; 199} 200EXTERN_C_END 201 202static napi_module demoModule = { 203 .nm_version = 1, 204 .nm_flags = 0, 205 .nm_filename = nullptr, 206 .nm_register_func = Init, 207 .nm_modname = "entry", 208 .nm_priv = ((void *)0), 209 .reserved = {0}, 210}; 211 212extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { 213 napi_module_register(&demoModule); 214} 215``` 216<!-- @[native_deserialize_sendable](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkTS/ArkTsConcurrent/ApplicationMultithreadingDevelopment/NativeInterthreadShared/entry/src/main/cpp/napi_init.cpp) --> 217 218 219``` 220// Index.d.ts 221export const testSendSendable: () => void; 222``` 223<!-- @[native_deserialize_sendable](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkTS/ArkTsConcurrent/ApplicationMultithreadingDevelopment/NativeInterthreadShared/entry/src/main/cpp/types/libentry/Index.d.ts) --> 224 225UI主线程发起调用。 226 227```ts 228// Index.ets 229import { hilog } from '@kit.PerformanceAnalysisKit'; 230import testNapi from 'libentry.so'; 231import { SendableObjTest } from './SendableObjTest' 232 233@Entry 234@Component 235struct Index { 236 @State message: string = 'Hello World'; 237 238 build() { 239 Row() { 240 Column() { 241 Text(this.message) 242 .fontSize(50) 243 .fontWeight(FontWeight.Bold) 244 .onClick(() => { 245 SendableObjTest.newSendable() 246 hilog.info(0x0000, 'testTag', 'Test send Sendable begin'); 247 testNapi.testSendSendable(); 248 hilog.info(0x0000, 'testTag', 'Test send Sendable end'); 249 }) 250 } 251 .width('100%') 252 } 253 .height('100%') 254 } 255} 256``` 257<!-- @[main_thread_init_call](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkTS/ArkTsConcurrent/ApplicationMultithreadingDevelopment/NativeInterthreadShared/entry/src/main/ets/pages/Index.ets) --> 258 259整个过程主要包括的逻辑实现为: 260 2611. 在UI主线程中创建ArkTS运行环境,并发起一个C++子线程创建Sendable对象,保存到result中,然后将result引用的Sendable对象序列化到全局序列化数据serializationData中。 262 2632. 当这些流程完成后,发起另外一个C++子线程,并在这个新的线程中创建ArkTS运行环境。然后再通过反序列化接口从serializationData中反序列化出UI主线程创建的Sendable对象,并保存到result中,从而实现了Sendable对象的跨C++线程传递。反序列化完成后,需要销毁反序列化数据避免内存泄露。这时UI主线程和子线程都同时持有这个Sendable共享对象,即可通过Node-API进行对象操作,比如读写或者传递到ArkTS层等。 264 265 > **说明:** 266 > 267 > 操作对象需要符合Sendable对象的规则,具体可见[Sendable使用规则与约束](sendable-constraints.md)。