C++线程间数据共享场景
============

在C++层进行多线程并发计算时，需要在每个C++线程上创建ArkTS执行环境，直接调用API。这样可以避免在非UI主线程回调时等待UI主线程的API调用结果。同时，还需要在C++线程之间共享和操作Sendable对象。

为了支持此类场景，C++线程需要能够创建并调用ArkTS，同时支持对Sendable对象进行多线程共享和操作。

#### 在C++线程上调用ArkTS能力

使用Node-API接口在C++线程中创建ArkTS运行环境并调用的方法，可以参考[使用Node-API接口创建ArkTS运行时环境](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/use-napi-ark-runtime)。

核心代码片段如下所示：

ArkTS文件定义。

@Sendable
export class SendableObjTest {
  static newSendable() {
    return 1024;
  }
}

实现Native加载ArkTS模块的能力。

#include <thread>

#include "napi/native\_api.h"

static void\* g\_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, &g\_serializationData);
    if (ret != napi\_ok) {
        std::abort();
    }
    return nullptr;
}

主要步骤包括：创建执行环境、加载模块、查找并调用模块函数（或直接通过Node-API接口创建Sendable对象），最后销毁执行环境。加载模块的详细信息，请参见[使用Node-API接口进行模块加载](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/use-napi-load-module-with-info)。查找并调用函数及更多Node-API接口能力，请参见[Node-API](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/napi)。

#### 在C++线程之间操作Sendable共享对象

在C++中调用ArkTS能力后，需要通过序列化和反序列化跨线程传递。napi\_value不是多线程安全的，不能直接在多线程之间操作和共享。

下面代码例子说明了如何序列化和反序列化传递对象，注意因为Sendable共享对象是引用传递，所以序列化不会产生另外一份拷贝数据，而是直接传递对象引用到反序列化线程，所以在性能上相比非Sendable对象的序列化和反序列化更为高效。

ArkTS文件定义。

@Sendable
export class SendableObjTest {
  static newSendable() {
    return 1024;
  }
}

在Native中实现两个线程的序列化和反序列化Sendable的逻辑。

#include <thread>

#include "napi/native\_api.h"

static void\* g\_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, &g\_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, g\_serializationData, &result);
    if (ret != napi\_ok) {
        std::abort();
    }
    // 3. 删除序列化数据
    ret = napi\_delete\_serialization\_data(env, g\_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);
    // 1024是判断ArkTS返回的结果是否正确
    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);
}

export const testSendSendable: () => void;

UI主线程发起调用。

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');
            this.message = 'success';
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

整个过程主要包括的逻辑实现为：

1.  在UI主线程中创建ArkTS运行环境，并发起一个C++子线程创建Sendable对象，保存到result中，然后将result引用的Sendable对象序列化到全局序列化数据serializationData中。
    
2.  当这些流程完成后，发起另外一个C++子线程，并在这个新的线程中创建ArkTS运行环境。然后再通过反序列化接口从serializationData中反序列化出UI主线程创建的Sendable对象，并保存到result中，从而实现了Sendable对象的跨C++线程传递。反序列化完成后，需要销毁反序列化数据避免内存泄露。这时UI主线程和子线程都同时持有这个Sendable共享对象，即可通过Node-API进行对象操作，比如读写或者传递到ArkTS层等。
    
    ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/14/v3/9MHRAaQlR0-vYxR64r7KRQ/note_3.0-zh-cn.png?HW-CC-KV=V1&HW-CC-Date=20260612T073248Z&HW-CC-Expire=86400&HW-CC-Sign=50F5D4D63F52E7F7C6D1EF229D896782570F49F199A75BE0046B2C9272D90F45)
    
    操作对象需要符合Sendable对象的规则，具体可见[Sendable使用规则与约束](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/sendable-constraints)。