HarmonyOS native 中执行长耗时任务收到中断信号,导致函数异常终止

操作步骤:

1、按照这个文档开发native模块:

https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/use-napi-asynchronous-task-V5

2、ExecuteCB中执行我们的业务逻辑 dowork()

  1. ArtTS中调用对应的接口

  2. ExecuteCB执行到dowork,当dowork执行到1秒时,执行被中断并伴随log:

05-29 18:34:19.458   3399-3417    C01719/ffrt                    com.examp...lication  W     [nodict]349:RecordSymbolAndBacktrace:114 Function occupies worker for more than 1s.
  • 1.

从log中看,worker是基于ffrt实现的,看了开源的

https://gitee.com/openharmony/resourceschedule_ffrt

是ffrt的长耗时任务监测触发的抓栈信号。

https://gitee.com/openharmony/resourceschedule_ffrt/blob/master/docs/user_guide.md

中,提到的sleep被中断唤醒的处理方式不适用于我们的场景:在dowork()函数中,包含与服务器交互逻辑,当收到中断时,与服务器连接状态都被重置,无法从断点恢复。

我们的需求:

能提供一个运行长耗时native任务的机制,且在执行过程中不被中断。

HarmonyOS
2024-12-27 15:35:52
968浏览
收藏 0
回答 1
回答 1
按赞同
/
按时间
FengTianYa

建议将这部分逻辑修改如下:

1.将与服务器交互逻辑在一个专门线程中处理。

2.业务逻辑处理完毕后,在通过线程安全函数将响应的信息返回给ArkTS层。

如下DEMO模拟了该过程,请根据项目实际情况,作相应修改:

index.d.ts文件:

export const jsRegister: (func: (data:number) => number) => void;
export const serviceNotifyFun: (data:number, type:number) => void;
Index.ets文件:
import { hilog } from '@kit.PerformanceAnalysisKit';
import testNapi from 'libentry.so';

@Entry
@Component
struct Index {
  @State message: string = 'Hello World';

  build() {
    Row() {
      Column() {
        Button("注册")
          .onClick(() => {
            testNapi.jsRegister((value: number) => {
              hilog.info(0x0000, 'testTag', 'js callback value:%{public}d', value);
              return (value + 11);
            })
          }).margin(10)

        Button("业务通知")
          .onClick(() => {
            for (let i:number = 0; i < 10; i++) {
              testNapi.serviceNotifyFun(i + 22, i + 55);
            }
          }).margin(10)
      }
      .width('100%')
    }
    .height('100%')
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.

napi_init.cpp文件:

#include "napi/native_api.h"
#define LOG_TAG "testTag"
#include "hilog/log.h"
#include <pthread.h>

pthread_mutex_t mutex_ = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_ = PTHREAD_COND_INITIALIZER;
// 指向napi_value js_cb
napi_ref cbObj = nullptr;
// 线程安全函数
napi_threadsafe_function tsfn;
static int cValue = 999;

typedef struct TestData {
int data;
int type;
} TestData;

struct lnode {
TestData data;
struct lnode *next;
};

struct linkQueue {
lnode *head;
lnode *tail;
int count;
};

struct linkQueue g_Queue;

static void InitQueue()
{
g_Queue.head = nullptr;
g_Queue.tail = nullptr;
g_Queue.count = 0;
}
static bool Push(TestData &data)
{
lnode *node = new lnode();
if (node == nullptr) {
return false;
}
node->next = nullptr;
node->data = data;

if (g_Queue.count == 0) {
g_Queue.head = node;
g_Queue.tail = node;
} else {
g_Queue.tail->next = node;
g_Queue.tail = node;
}
g_Queue.count++;
return true;
}

static TestData *Pop()
{
if (g_Queue.count == 0) {
return nullptr;
}
lnode *node = g_Queue.head;
g_Queue.count--;
g_Queue.head = g_Queue.head->next;
TestData *data = new TestData();
if (data == nullptr) {
delete node;
return nullptr;
}
*data = node->data;
delete node;
return data;
}

bool IsEmpty()
{
return g_Queue.count == 0;
}
static napi_value ServiceNotifyFun(napi_env env, napi_callback_info info) {
if (cbObj == nullptr) {
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG, "cbObj == nullptr");
return nullptr;
}
size_t argc = 2;
napi_value args[2] = {nullptr};

napi_value ets_fun;
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

TestData testData;
napi_get_value_int32(env, args[0], &testData.data);
napi_get_value_int32(env, args[1], &testData.type);

OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG, "ServiceNotifyFun:%{public}d,type:%{public}d", testData.data, testData.type);

pthread_mutex_lock(&mutex_);
Push(testData);
pthread_mutex_unlock(&mutex_);
pthread_cond_signal(&cond_);

return nullptr;
}

// 回调
static void CallJs(napi_env env, napi_value js_cb, void *context, void *data) {
TestData *testDatal = (TestData *)data;

OH_LOG_INFO(LOG_APP, "CallJs, data=%{public}d, type:%{public}d", testDatal->data, testDatal->type);
delete testDatal;

OH_LOG_Print(LOG_APP, LOG_WARN, LOG_DOMAIN, "testTag", "enter CallJs");

// 获取引用值
napi_get_reference_value(env, cbObj, &js_cb);

// 创建一个ArkTS number作为ArkTS function的入参。
napi_value argv;
napi_create_int32(env, cValue, &argv);

napi_value result = nullptr;
napi_call_function(env, nullptr, js_cb, 1, &argv, &result);

napi_get_value_int32(env, result, &cValue);

OH_LOG_Print(LOG_APP, LOG_WARN, LOG_DOMAIN, "testTag", "end CallJs, result:%{public}d", cValue);
}
static void *ServiceHandle(void *args) {
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG, "start thread_call");

pthread_detach(pthread_self());

TestData *testData = nullptr;

while (true) {
pthread_mutex_lock(&mutex_);
pthread_cond_wait(&cond_, &mutex_);
while (!IsEmpty()) {
testData = Pop();
if (testData == nullptr) {
break;
}
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG, "service Handle");
napi_acquire_threadsafe_function(tsfn);
napi_call_threadsafe_function(tsfn, testData, napi_tsfn_blocking);
testData = nullptr;
}
pthread_mutex_unlock(&mutex_);
}
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG, "end thread_call");

return nullptr;
}

static napi_value JsRegister(napi_env env, napi_callback_info info) {
OH_LOG_INFO(LOG_APP, "start JsRegister");

// 从ArkTS侧获取的参数的数量
size_t argc = 1;
napi_value js_cb, work_name;

// 获取ArkTS参数
napi_get_cb_info(env, info, &argc, &js_cb, nullptr, nullptr);

// 指向napi_value js_cb 的 napi_ref cbObj
napi_create_reference(env, js_cb, 1, &cbObj);

// 通过UTF8编码的C字符串数据创建work_name
napi_create_string_utf8(env, "Work Item", NAPI_AUTO_LENGTH, &work_name);

// 创建线程安全函数
napi_create_threadsafe_function(env, js_cb, NULL, work_name, 0, 1, NULL, NULL, NULL, CallJs, &tsfn);

OH_LOG_INFO(LOG_APP, "end JsRegister");

return nullptr;
}
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
napi_property_descriptor desc[] = {
{ "jsRegister", nullptr, JsRegister, nullptr, nullptr, nullptr, napi_default, nullptr },
{ "serviceNotifyFun", nullptr, ServiceNotifyFun, nullptr, nullptr, nullptr, napi_default, nullptr }
};
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);

InitQueue();
pthread_t tid;
pthread_create(&tid, NULL, &ServiceHandle, NULL);

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);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
  • 191.
  • 192.
  • 193.
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.
  • 206.
  • 207.
  • 208.

CMakeLists.txt文件:

# the minimum version of CMake.
cmake_minimum_required(VERSION 3.4.1)
project(napi_call_threadsafe_function)

set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})

if(DEFINED PACKAGE_FIND_FILE)
include(${PACKAGE_FIND_FILE})
endif()

include_directories(${NATIVERENDER_ROOT_PATH}
${NATIVERENDER_ROOT_PATH}/include)

add_library(entry SHARED napi_init.cpp)
target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
分享
微博
QQ
微信
回复
2024-12-27 17:14:44


相关问题
在arkts如何执行耗时任务
298浏览 • 1回复 待解决
HarmonyOS 主线程耗时任务,app闪退
886浏览 • 1回复 待解决
HarmonyOS时任务
675浏览 • 1回复 待解决
HarmonyOS nativesvg解码异常
955浏览 • 1回复 待解决
后台长时任务启动失败
3018浏览 • 1回复 待解决