• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# C++ Inter-Thread Data Sharing
2
3When an application performs multithreaded computations at the C++ layer, ArkTS APIs needs to be executed within the ArkTS environment. To prevent the non-UI main thread from waiting for the API call results within the ArkTS environment of the UI main thread, you need to create an ArkTS execution environment on these C++ threads and directly call the APIs. In addition, you may need to share and manipulate Sendable objects across C++ threads.
4
5To support this scenario, you must create the capabilities to call ArkTS APIs on C++ threads, and share and manipulate Sendable objects across threads.
6
7
8## Calling ArkTS APIs on C++ Threads
9
10For details about how to use Node-API to create an ArkTS runtime environment and call ArkTS APIs on C++ threads, see [Creating an ArkTS Runtime Environment Using Node-API](../napi/use-napi-ark-runtime.md).
11
12The core code snippet is as follows:
13
14ArkTS file definition
15
16```ts
17// SendableObjTest.ets
18@Sendable
19export class SendableObjTest {
20  static newSendable() {
21    return 1024;
22  }
23}
24```
25
26
27Native implementation to load ArkTS modules
28
29```cpp
30// napi_init.cpp
31#include "napi/native_api.h"
32#include <thread>
33static void *CreateArkRuntimeFunc(void *arg)
34{
35    // 1. Create the ArkTS runtime environment.
36    napi_env env = nullptr;
37    napi_status ret = napi_create_ark_runtime(&env);
38    if (ret != napi_ok) {
39        std::abort();
40    }
41    // 2. Load the custom module, assuming that SendableObjTest provides the newSendable function for creating Sendable objects.
42    napi_value test = nullptr;
43    ret = napi_load_module_with_info(env, "entry/src/main/ets/pages/SendableObjTest", "com.example.myapplication/entry", &test);
44    if (ret != napi_ok) {
45        std::abort();
46    }
47    napi_value sendableObjTest = nullptr;
48    ret = napi_get_named_property(env, test, "SendableObjTest", &sendableObjTest);
49    if (ret != napi_ok) {
50        std::abort();
51    }
52    // 3. Use newSendable in ArkTS, assuming that the newSendable function in sendableObjTest returns a Sendable object.
53    napi_value newSendable = nullptr;
54    ret = napi_get_named_property(env, sendableObjTest, "newSendable", &newSendable);
55    if (ret != napi_ok) {
56        std::abort();
57    }
58    // 4. Call the newSendable function to return the newly created Sendable object and store it in result.
59    napi_value result = nullptr;
60    ret = napi_call_function(env, sendableObjTest, newSendable, 0, nullptr, &result);
61    if (ret != napi_ok) {
62        std::abort();
63    }
64    // 5. Obtain the result returned by ArkTS.
65    int value0;
66    napi_get_value_int32(env, result, &value0);
67    if (value0 != 1024) {
68        std::abort();
69    }
70    // 6. Destroy the ArkTS runtime environment.
71    ret = napi_destroy_ark_runtime(&env);
72    return nullptr;
73}
74```
75
76The process consists of four steps: creating an execution environment, loading modules, searching for and calling functions (or directly creating Sendable objects through Node-API), and finally destroying the execution environment. For details about how to load modules, see [Loading a Module Using Node-API](../napi/use-napi-load-module-with-info.md). For details about how to search for and call functions and more Node-API capabilities, see [Node-API](../reference/native-lib/napi.md).
77
78## Manipulating Sendable Objects Across C++ Threads
79
80After implementing the capabilities to call ArkTS APIs from C++, serialize and deserialize objects for cross-thread transfer. The **napi_value** variable cannot be directly shared across threads because it is not thread-safe.
81
82The following code example demonstrates how to serialize and deserialize objects. Since Sendable objects are passed by reference, serialization does not create an additional copy of the data but directly passes the object reference to the deserializing thread. This makes serialization and deserialization more efficient than non-Sendable objects.
83
84ArkTS file definition
85
86```ts
87// SendableObjTest.ets
88@Sendable
89export class SendableObjTest {
90  static newSendable() {
91    return 1024;
92  }
93}
94```
95
96Native implementation for serialization and deserialization of Sendable objects
97
98```cpp
99// napi_init.cpp
100#include "napi/native_api.h"
101#include <thread>
102
103static void *serializationData = nullptr;
104static void *CreateEnvAndSendSendable(void *) {
105    // 1. Create the ArkTS runtime environment.
106    napi_env env = nullptr;
107    napi_status ret = napi_create_ark_runtime(&env);
108    if (ret != napi_ok) {
109        std::abort();
110    }
111    // 2. Load the custom module, assuming that SendableObjTest provides the newSendable function for creating Sendable objects.
112    napi_value test = nullptr;
113    ret = napi_load_module_with_info(env, "entry/src/main/ets/pages/SendableObjTest", "com.example.myapplication/entry",
114                                     &test);
115    if (ret != napi_ok) {
116        std::abort();
117    }
118    napi_value sendableObjTest = nullptr;
119    ret = napi_get_named_property(env, test, "SendableObjTest", &sendableObjTest);
120    if (ret != napi_ok) {
121        std::abort();
122    }
123    // 3. Use newSendable in ArkTS, assuming that the newSendable function in sendableObjTest returns a Sendable object.
124    napi_value newSendable = nullptr;
125    ret = napi_get_named_property(env, sendableObjTest, "newSendable", &newSendable);
126    if (ret != napi_ok) {
127        std::abort();
128    }
129    // 4. Call the newSendable function to return the newly created Sendable object and store it in result.
130    napi_value result = nullptr;
131    ret = napi_call_function(env, sendableObjTest, newSendable, 0, nullptr, &result);
132    if (ret != napi_ok) {
133        std::abort();
134    }
135    // 5. Serialize the Sendable object.
136    napi_value undefined;
137    napi_get_undefined(env, &undefined);
138    ret = napi_serialize(env, result, undefined, undefined, &serializationData);
139    if (ret != napi_ok) {
140        std::abort();
141    }
142    return nullptr;
143}
144
145static void *CreateEnvAndReceiveSendable(void *) {
146    // 1. Create the ArkTS runtime environment.
147    napi_env env = nullptr;
148    napi_status ret = napi_create_ark_runtime(&env);
149    if (ret != napi_ok) {
150        std::abort();
151    }
152    // 2. Deserialize the Sendable object and store it in result, which can then be manipulated via Node-API.
153    napi_value result = nullptr;
154    ret = napi_deserialize(env, serializationData, &result);
155    if (ret != napi_ok) {
156        std::abort();
157    }
158    // 3. Delete the serialization data.
159    ret = napi_delete_serialization_data(env, serializationData);
160    if (ret != napi_ok) {
161        std::abort();
162    }
163    napi_valuetype valuetype0;
164    napi_typeof(env, result, &valuetype0);
165    if (valuetype0 != napi_number) {
166        std::abort();
167    }
168    int value0;
169    napi_get_value_int32(env, result, &value0);
170    if (value0 != 1024) {
171        std::abort();
172    }
173    return nullptr;
174}
175
176static napi_value TestSendSendable([[maybe_unused]] napi_env env, [[maybe_unused]] napi_callback_info info) {
177    std::thread t1(CreateEnvAndSendSendable, nullptr);
178    t1.join();
179    std::thread t2(CreateEnvAndReceiveSendable, nullptr);
180    t2.join();
181    return nullptr;
182}
183
184EXTERN_C_START
185static napi_value Init(napi_env env, napi_value exports) {
186    napi_property_descriptor desc[] = {
187        {"testSendSendable", nullptr, TestSendSendable, nullptr, nullptr, nullptr, napi_default, nullptr}};
188    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
189    return exports;
190}
191EXTERN_C_END
192
193static napi_module demoModule = {
194    .nm_version = 1,
195    .nm_flags = 0,
196    .nm_filename = nullptr,
197    .nm_register_func = Init,
198    .nm_modname = "entry",
199    .nm_priv = ((void *)0),
200    .reserved = {0},
201};
202
203extern "C" __attribute__((constructor)) void RegisterEntryModule(void) {
204    napi_module_register(&demoModule);
205}
206```
207
208
209```
210// Index.d.ts
211export const testSendSendable: () => void;
212```
213
214UI main thread invocation
215
216```ts
217// Index.ets
218import { hilog } from '@kit.PerformanceAnalysisKit';
219import testNapi from 'libentry.so';
220import { SendableObjTest } from './SendableObjTest'
221
222@Entry
223@Component
224struct Index {
225  @State message: string = 'Hello World';
226
227  build() {
228    Row() {
229      Column() {
230        Text(this.message)
231          .fontSize(50)
232          .fontWeight(FontWeight.Bold)
233          .onClick(() => {
234            SendableObjTest.newSendable()
235            hilog.info(0x0000, 'testTag', 'Test send Sendable begin');
236            testNapi.testSendSendable();
237            hilog.info(0x0000, 'testTag', 'Test send Sendable end');
238          })
239      }
240      .width('100%')
241    }
242    .height('100%')
243  }
244}
245```
246
247The logic implementation of the entire process is as follows:
248
2491. In the UI main thread where the **main** function resides, create an ArkTS runtime environment and initiate a C++child thread to create a Sendable object and store the object in **result**. Serialize the Sendable object referenced by **result** into global serialization data **serializationData**.
250
2512. After the preceding steps are complete, initiate another C++ child thread. In this new thread, create the ArkTS runtime environment. Then, deserialize the Sendable object created in the UI main thread from **serializationData** using the deserialization interface and store it in **result**. This enables the transfer of Sendable objects across C++ thread. After deserialization, the deserialization data must be destroyed to prevent memory leaks. In this case, both the UI main thread and the child thread hold the Sendable object, which can be manipulated via Node-API, such as reading/writing or passing it to the ArkTS layer.
252
253   > **NOTE**
254   >
255   > The object being manipulated must comply with the rules of Sendable objects. For details, see [Usage Rules and Constraints for Sendable](sendable-constraints.md).
256