• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)。