harmony 鸿蒙C++线程间数据共享场景
C++线程间数据共享场景
当应用在C++层进行多线程并发计算时,因为ArkTS的API需要在ArkTS环境中执行,为了避免在非UI主线程每次回调时等待UI主线程的API调用结果,需要在这些C++线程上创建ArkTS执行环境并直接调用API。此外,可能需要在C++线程之间共享和操作Sendable对象。
为了支持此类场景,C++线程需具备创建调用ArkTS的能力,并对Sendable对象进行多线程共享和操作。
在C++线程上调用ArkTS能力
关于如何使用Node-API接口在C++线程创建ArkTS运行环境并调用,开发者可以参考使用Node-API接口创建ArkTS运行时环境。
核心代码片段如下所示:
ArkTS文件定义。
// SendableObjTest.ets
@Sendable
export class SendableObjTest {
static newSendable() {
return 1024;
}
}
实现Native加载ArkTS模块的能力。
// napi_init.cpp
#include "napi/native_api.h"
#include <thread>
static void *CreateArkRuntimeFunc(void *arg)
{
// 1. 创建基础运行环境
napi_env env = nullptr;
napi_status ret = napi_create_ark_runtime(&env);
if (ret != napi_ok) {
std::abort();
}
// 2. 加载自定义模块,假定SendableObjTest中提供创建sendable对象的方法newSendable
napi_value test = nullptr;
ret = napi_load_module_with_info(env, "entry/src/main/ets/pages/SendableObjTest", "com.example.myapplication/entry", &test);
if (ret != napi_ok) {
std::abort();
}
napi_value sendableObjTest = nullptr;
ret = napi_get_named_property(env, test, "SendableObjTest", &sendableObjTest);
if (ret != napi_ok) {
std::abort();
}
// 3. 使用ArkTS中的newSendable,假设sendableObjTest中有一个函数newSendable能返回sendable对象
napi_value newSendable = nullptr;
ret = napi_get_named_property(env, sendableObjTest, "newSendable", &newSendable);
if (ret != napi_ok) {
std::abort();
}
// 4. 调用newSendable函数返回新创建的sendable对象,并保存在result中
napi_value result = nullptr;
ret = napi_call_function(env, sendableObjTest, newSendable, 0, nullptr, &result);
if (ret != napi_ok) {
std::abort();
}
// 5. 获取ArkTS返回的结果
int value0;
napi_get_value_int32(env, result, &value0);
if (value0 != 1024) {
std::abort();
}
// 6. 销毁ArkTS环境
ret = napi_destroy_ark_runtime(&env);
return nullptr;
}
主要步骤包括:创建执行环境、加载模块、查找并调用模块函数(也可以直接通过Node-API接口创建Sendable对象),最后销毁执行环境。关于第二步加载模块的详细信息,请参见使用Node-API接口进行模块加载。关于第三步查找并调用函数及更多Node-API接口能力,请参见Node-API。
在C++线程之间操作Sendable共享对象
实现在C++调用ArkTS能力后,需要通过序列化和反序列化跨线程传递。napi_value不是多线程安全的,不能直接在多线程之间共享。
下面代码例子说明了如何序列化和反序列化传递对象,注意因为Sendable共享对象是引用传递,所以序列化不会产生另外一份拷贝数据,而是直接传递对象引用到反序列化线程,所以在性能上相比非Sendable对象的序列化和反序列化更为高效。
ArkTS文件定义。
// SendableObjTest.ets
@Sendable
export class SendableObjTest {
static newSendable() {
return 1024;
}
}
在Native中实现两个线程的序列化和反序列化Sendable的逻辑。
// napi_init.cpp
#include "napi/native_api.h"
#include <thread>
static void *serializationData = nullptr;
static void *CreateEnvAndSendSendable(void *) {
// 1. 创建基础运行环境
napi_env env = nullptr;
napi_status ret = napi_create_ark_runtime(&env);
if (ret != napi_ok) {
std::abort();
}
// 2. 加载自定义模块,假定SendableObjTest中提供创建sendable对象的方法newSendable
napi_value test = nullptr;
ret = napi_load_module_with_info(env, "entry/src/main/ets/pages/SendableObjTest", "com.example.myapplication/entry",
&test);
if (ret != napi_ok) {
std::abort();
}
napi_value sendableObjTest = nullptr;
ret = napi_get_named_property(env, test, "SendableObjTest", &sendableObjTest);
if (ret != napi_ok) {
std::abort();
}
// 3. 使用ArkTS中的newSendable,假设sendableObjTest中有一个函数newSendable能返回sendable对象
napi_value newSendable = nullptr;
ret = napi_get_named_property(env, sendableObjTest, "newSendable", &newSendable);
if (ret != napi_ok) {
std::abort();
}
// 4. 调用newSendable函数返回新创建的sendable对象,并保存在result中
napi_value result = nullptr;
ret = napi_call_function(env, sendableObjTest, newSendable, 0, nullptr, &result);
if (ret != napi_ok) {
std::abort();
}
// 5. 序列化sendable对象
napi_value undefined;
napi_get_undefined(env, &undefined);
ret = napi_serialize(env, result, undefined, undefined, &serializationData);
if (ret != napi_ok) {
std::abort();
}
return nullptr;
}
static void *CreateEnvAndReceiveSendable(void *) {
// 1. 创建基础运行环境
napi_env env = nullptr;
napi_status ret = napi_create_ark_runtime(&env);
if (ret != napi_ok) {
std::abort();
}
// 2. 反序列化获取sendable共享对象,结果保存在result中,这个result就可以通过napi接口进行各种操作了
napi_value result = nullptr;
ret = napi_deserialize(env, serializationData, &result);
if (ret != napi_ok) {
std::abort();
}
// 3. 删除序列化数据
ret = napi_delete_serialization_data(env, serializationData);
if (ret != napi_ok) {
std::abort();
}
napi_valuetype valuetype0;
napi_typeof(env, result, &valuetype0);
if (valuetype0 != napi_number) {
std::abort();
}
int value0;
napi_get_value_int32(env, result, &value0);
if (value0 != 1024) {
std::abort();
}
return nullptr;
}
static napi_value TestSendSendable([[maybe_unused]] napi_env env, [[maybe_unused]] napi_callback_info info) {
std::thread t1(CreateEnvAndSendSendable, nullptr);
t1.join();
std::thread t2(CreateEnvAndReceiveSendable, nullptr);
t2.join();
return nullptr;
}
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
napi_property_descriptor desc[] = {
{"testSendSendable", nullptr, TestSendSendable, nullptr, nullptr, nullptr, napi_default, nullptr}};
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
return exports;
}
EXTERN_C_END
static napi_module demoModule = {
.nm_version = 1,
.nm_flags = 0,
.nm_filename = nullptr,
.nm_register_func = Init,
.nm_modname = "entry",
.nm_priv = ((void *)0),
.reserved = {0},
};
extern "C" __attribute__((constructor)) void RegisterEntryModule(void) {
napi_module_register(&demoModule);
}
// Index.d.ts
export const testSendSendable: () => void;
UI主线程发起调用。
// Index.ets
import { hilog } from '@kit.PerformanceAnalysisKit';
import testNapi from 'libentry.so';
import { SendableObjTest } from './SendableObjTest'
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(() => {
SendableObjTest.newSendable()
hilog.info(0x0000, 'testTag', 'Test send Sendable begin');
testNapi.testSendSendable();
hilog.info(0x0000, 'testTag', 'Test send Sendable end');
})
}
.width('100%')
}
.height('100%')
}
}
整个过程主要包括的逻辑实现为:
在入口main函数所在的UI主线程中创建ArkTS运行环境,并发起一个C++子线程创建Sendable对象,保存到result中,然后将result引用的Sendable对象序列化到全局序列化数据serializationData中。
当这些流程完成后,发起另外一个C++子线程,并在这个新的线程中创建ArkTS运行环境。然后再通过反序列化接口从serializationData中反序列化出UI主线程创建的Sendable对象,并保存到result中,从而实现了Sendable对象的跨C++线程传递。反序列化完成后,需要销毁反序列化数据避免内存泄露。这时UI主线程和子线程都同时持有这个Sendable共享对象,即可通过Node-API进行对象操作,比如读写或者传递到ArkTS层等。
说明:
操作对象需要符合Sendable对象的规则,具体可见Sendable使用规则与约束。
你可能感兴趣的鸿蒙文章
- 所属分类: 后端技术
- 本文标签:
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
8、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦