diff --git a/code/Performance/PerformanceLibrary/feature/nativeThreadsCallJS/src/main/cpp/hello.cpp b/code/Performance/PerformanceLibrary/feature/nativeThreadsCallJS/src/main/cpp/hello.cpp index 53445802f..3a38e0cb9 100644 --- a/code/Performance/PerformanceLibrary/feature/nativeThreadsCallJS/src/main/cpp/hello.cpp +++ b/code/Performance/PerformanceLibrary/feature/nativeThreadsCallJS/src/main/cpp/hello.cpp @@ -20,8 +20,8 @@ #include napi_threadsafe_function tsfn; // 线程安全函数 -static int cValue; // 保存ark_ts最新的值,作为调用js函数的参数 -int THREAD_NUM = 3; // 线程数 +static int g_cValue; // 保存value最新的值,作为参数传给js回调函数 +int g_threadNum = 3; // 线程数 struct CallbackContext { napi_env env = nullptr; @@ -29,7 +29,65 @@ struct CallbackContext { int retData = 0; }; -void callbackUvWorkTest(CallbackContext *context) { +void WorkCallback(uv_work_t *workReq) +{ + // 另外一个子线程,一些耗时操作可以在此进行. 此处不能调用js函数. + CallbackContext *context = (CallbackContext *)workReq->data; + if (context != nullptr) { + OH_LOG_INFO(LOG_APP, "UvWorkTest CallBack1 childThread_2 [%{public}d]", context->retData); + context->retData++; + OH_LOG_INFO(LOG_APP, "UvWorkTest CallBack2 childThread_2 [%{public}d]", context->retData); + } else { + OH_LOG_INFO(LOG_APP, "UvWorkTest CallBack3 childThread_2 context is null."); + } +} + +void AfterWorkCallback(uv_work_t *workReq, int status) +{ + CallbackContext *context = (CallbackContext *)workReq->data; + // 主线程执行,可以在此调用js函数 + OH_LOG_INFO(LOG_APP, "UvWorkTest CallBack mainThread [%{public}d]", context->retData); + napi_handle_scope scope = nullptr; + napi_open_handle_scope(context->env, &scope); + if (scope == nullptr) { + if (context != nullptr) { + napi_delete_reference(context->env, context->callbackRef); + delete context; + context = nullptr; + } + if (workReq != nullptr) { + delete workReq; + workReq = nullptr; + } + return; + } + napi_value callback = nullptr; + napi_get_reference_value(context->env, context->callbackRef, &callback); + napi_value retArg; + OH_LOG_INFO(LOG_APP, "UvWorkTest CallBack begin [%{public}d]", g_cValue); + napi_create_int32(context->env, g_cValue, &retArg); + napi_value ret; + napi_call_function(context->env, nullptr, callback, 1, &retArg, &ret); + // 保存js回调结果 + napi_get_value_int32(context->env, ret, &g_cValue); + OH_LOG_INFO(LOG_APP, "UvWorkTest CallBack end [%{public}d]", g_cValue); + + napi_close_handle_scope(context->env, scope); + if (context != nullptr) { + napi_delete_reference(context->env, context->callbackRef); + delete context; + OH_LOG_INFO(LOG_APP, "UvWorkTest delete context"); + context = nullptr; + } + if (workReq != nullptr) { + delete workReq; + OH_LOG_INFO(LOG_APP, "UvWorkTest delete work"); + workReq = nullptr; + } +} + +void CallbackUvWorkTest(CallbackContext *context) +{ if (context == nullptr) { OH_LOG_ERROR(LOG_APP, "UvWorkTest context is nullptr"); return; @@ -37,8 +95,8 @@ void callbackUvWorkTest(CallbackContext *context) { uv_loop_s *loop = nullptr; napi_get_uv_event_loop(context->env, &loop); // 创建工作数据结构,自定义数据结构添加在data中 - uv_work_t *work = new uv_work_t; - if (work == nullptr) { + uv_work_t *workReq = new uv_work_t; + if (workReq == nullptr) { if (context != nullptr) { napi_delete_reference(context->env, context->callbackRef); delete context; @@ -48,70 +106,16 @@ void callbackUvWorkTest(CallbackContext *context) { OH_LOG_ERROR(LOG_APP, "UvWorkTest new uv_work_t fail!"); return; } - work->data = (void *)context; + workReq->data = (void *)context; // 此打印位于子线程 - OH_LOG_INFO(LOG_APP, "UvWorkTest childThread_1 [%{public}d]", cValue); + OH_LOG_INFO(LOG_APP, "UvWorkTest childThread_1 [%{public}d]", g_cValue); // 添加工作任务到libuv的队列中 - uv_queue_work( - loop, work, - [](uv_work_t *work) { - // 另外一个子线程,一些耗时操作可以在此进行,此处对参数进行加10000操作. 此处不能调用js函数. - CallbackContext *context = (CallbackContext *)work->data; - if (context != nullptr) { - OH_LOG_INFO(LOG_APP, "UvWorkTest CallBack1 childThread_2 [%{public}d]", context->retData); - context->retData += 10000; - OH_LOG_INFO(LOG_APP, "UvWorkTest CallBack2 childThread_2 [%{public}d]", context->retData); - } else { - OH_LOG_INFO(LOG_APP, "UvWorkTest CallBack3 childThread_2 context is null."); - } - }, - // using callback function back to JS thread - [](uv_work_t *work, int status) { - CallbackContext *context = (CallbackContext *)work->data; - // 执行完上面其他线程的回调之后,回到主线程执行,可以在此调用js函数 - OH_LOG_INFO(LOG_APP, "UvWorkTest CallBack mainThread [%{public}d]", context->retData); - napi_handle_scope scope = nullptr; - napi_open_handle_scope(context->env, &scope); - if (scope == nullptr) { - if (context != nullptr) { - napi_delete_reference(context->env, context->callbackRef); - delete context; - context = nullptr; - } - if (work != nullptr) { - delete work; - work = nullptr; - } - return; - } - napi_value callback = nullptr; - napi_get_reference_value(context->env, context->callbackRef, &callback); - napi_value retArg; - OH_LOG_INFO(LOG_APP, "UvWorkTest CallBack begin [%{public}d]", cValue); - napi_create_int32(context->env, cValue, &retArg); - napi_value ret; - napi_call_function(context->env, nullptr, callback, 1, &retArg, &ret); - // 保存js回调结果 - napi_get_value_int32(context->env, ret, &cValue); - OH_LOG_INFO(LOG_APP, "UvWorkTest CallBack end [%{public}d]", cValue); - - napi_close_handle_scope(context->env, scope); - if (context != nullptr) { - napi_delete_reference(context->env, context->callbackRef); - delete context; - OH_LOG_INFO(LOG_APP, "UvWorkTest delete context"); - context = nullptr; - } - if (work != nullptr) { - delete work; - OH_LOG_INFO(LOG_APP, "UvWorkTest delete work"); - work = nullptr; - } - }); + uv_queue_work(loop, workReq, WorkCallback, AfterWorkCallback); } // 使用uv_work callback 实现跨线程调用js函数 -static napi_value UvWorkTest(napi_env env, napi_callback_info info) { +static napi_value UvWorkTest(napi_env env, napi_callback_info info) +{ size_t argc = 1; napi_value argv[1] = {0}; napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr); @@ -123,8 +127,8 @@ static napi_value UvWorkTest(napi_env env, napi_callback_info info) { return nullptr; } - OH_LOG_INFO(LOG_APP, "UvWorkTest current value:[%{public}d]", cValue); - for (int i = 0; i < THREAD_NUM; i++) { + OH_LOG_INFO(LOG_APP, "UvWorkTest current value:[%{public}d]", g_cValue); + for (int i = 0; i < g_threadNum; i++) { auto asyncContext = new CallbackContext(); if (asyncContext == nullptr) { OH_LOG_ERROR(LOG_APP, "UvWorkTest new asyncContext fail!"); @@ -132,24 +136,25 @@ static napi_value UvWorkTest(napi_env env, napi_callback_info info) { } asyncContext->env = env; asyncContext->retData = i; - OH_LOG_INFO(LOG_APP, "UvWorkTest thread begin index:[%{public}d], value:[%{public}d]", i, cValue); + OH_LOG_INFO(LOG_APP, "UvWorkTest thread begin index:[%{public}d], value:[%{public}d]", i, g_cValue); napi_create_reference(env, argv[0], 1, &asyncContext->callbackRef); // using callback function on other thread - std::thread testThread(callbackUvWorkTest, asyncContext); + std::thread testThread(CallbackUvWorkTest, asyncContext); testThread.detach(); - OH_LOG_INFO(LOG_APP, "UvWorkTest thread end index:[%{public}d], value:[%{public}d]", i, cValue); + OH_LOG_INFO(LOG_APP, "UvWorkTest thread end index:[%{public}d], value:[%{public}d]", i, g_cValue); } return nullptr; } // 安全函数回调 -static void ThreadSafeCallJs(napi_env env, napi_value js_cb, void *context, void *data) { +static void ThreadSafeCallJs(napi_env env, napi_value js_cb, void *context, void *data) +{ CallbackContext *argContent = (CallbackContext *)data; if (argContent != nullptr) { OH_LOG_INFO(LOG_APP, "ThreadSafeTest CallJs start, retData:[%{public}d]", argContent->retData); napi_get_reference_value(env, argContent->callbackRef, &js_cb); } else { - OH_LOG_INFO(LOG_APP, "ThreadSafeTest CallJs_0 argContent is null"); + OH_LOG_INFO(LOG_APP, "ThreadSafeTest CallJs argContent is null"); return; } @@ -161,18 +166,18 @@ static void ThreadSafeCallJs(napi_env env, napi_value js_cb, void *context, void napi_delete_reference(env, argContent->callbackRef); delete argContent; argContent = nullptr; - OH_LOG_INFO(LOG_APP, "ThreadSafeTest delete argContent 1"); + OH_LOG_INFO(LOG_APP, "ThreadSafeTest delete argContent"); } return; } // 将当前value值作为参数调用js函数 napi_value argv; - napi_create_int32(env, cValue, &argv); + napi_create_int32(env, g_cValue, &argv); napi_value result = nullptr; napi_call_function(env, nullptr, js_cb, 1, &argv, &result); - // cValue保存调用js后的返回结果 - napi_get_value_int32(env, result, &cValue); - OH_LOG_INFO(LOG_APP, "ThreadSafeTest CallJs end, [%{public}d]", cValue); + // g_cValue保存调用js后的返回结果 + napi_get_value_int32(env, result, &g_cValue); + OH_LOG_INFO(LOG_APP, "ThreadSafeTest CallJs end, [%{public}d]", g_cValue); if (argContent != nullptr) { napi_delete_reference(env, argContent->callbackRef); delete argContent; @@ -182,9 +187,11 @@ static void ThreadSafeCallJs(napi_env env, napi_value js_cb, void *context, void } // 使用安全函数跨线程调用js函数 -static napi_value ThreadSafeTest(napi_env env, napi_callback_info info) { +static napi_value ThreadSafeTest(napi_env env, napi_callback_info info) +{ size_t argc = 1; - napi_value js_cb, workName; + napi_value js_cb; + napi_value workName; // 获取ArkTS 参数 napi_get_cb_info(env, info, &argc, &js_cb, nullptr, nullptr); // 判断参数类型 @@ -194,35 +201,35 @@ static napi_value ThreadSafeTest(napi_env env, napi_callback_info info) { OH_LOG_ERROR(LOG_APP, "ThreadSafeTest callback param is not function"); return nullptr; } - OH_LOG_INFO(LOG_APP, "ThreadSafeTest current value: [%{public}d]", cValue); + OH_LOG_INFO(LOG_APP, "ThreadSafeTest current value: [%{public}d]", g_cValue); // 使用安全线程跨线程调用js 函数 napi_create_string_utf8(env, "workItem", NAPI_AUTO_LENGTH, &workName); // 创建线程安全函数 napi_create_threadsafe_function(env, js_cb, NULL, workName, 0, 1, NULL, NULL, NULL, ThreadSafeCallJs, &tsfn); // 在子线程中调用线程安全函数 - for (int i = 0; i < THREAD_NUM; i++) { + for (int i = 0; i < g_threadNum; i++) { // 创建回调参数 auto asyncContext = new CallbackContext(); asyncContext->env = env; asyncContext->retData = i; napi_create_reference(env, js_cb, 1, &asyncContext->callbackRef); std::thread t([asyncContext]() { - // 处理业务逻辑,此次简单的加10000 + // 处理业务逻辑 OH_LOG_INFO(LOG_APP, "ThreadSafeTest ChildTread start, index:[%{public}d], value: [%{public}d]", - asyncContext->retData, cValue); - asyncContext->retData += 10000; + asyncContext->retData, g_cValue); + asyncContext->retData++; // 请求线程安全函数 napi_acquire_threadsafe_function(tsfn); // 调用线程安全函数 napi_call_threadsafe_function(tsfn, asyncContext, napi_tsfn_nonblocking); OH_LOG_INFO(LOG_APP, "ThreadSafeTest ChildTread end, index:[%{public}d], value: [%{public}d]", - asyncContext->retData, cValue); + asyncContext->retData, g_cValue); /* 以下直接在子线程中调用js函数,会崩溃 napi_value result = nullptr; napi_value argv; - napi_create_int32(env,cValue, &argv); + napi_create_int32(env,g_cValue, &argv); napi_call_function(env, nullptr, js_cb, 1, &argv, &result); */ }); @@ -239,7 +246,8 @@ static napi_value ThreadSafeTest(napi_env env, napi_callback_info info) { } EXTERN_C_START -static napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) +{ // 第一个参数"add"为ArkTS侧对应方法的名称。 napi_property_descriptor desc[] = { {"UvWorkTest", nullptr, UvWorkTest, nullptr, nullptr, nullptr, napi_default, nullptr}, diff --git a/code/Performance/PerformanceLibrary/feature/nativeThreadsCallJS/src/main/ets/pages/Index.ets b/code/Performance/PerformanceLibrary/feature/nativeThreadsCallJS/src/main/ets/pages/Index.ets index 7318d7681..f1dba5788 100644 --- a/code/Performance/PerformanceLibrary/feature/nativeThreadsCallJS/src/main/ets/pages/Index.ets +++ b/code/Performance/PerformanceLibrary/feature/nativeThreadsCallJS/src/main/ets/pages/Index.ets @@ -14,7 +14,7 @@ */ import entry from 'libentry.so'; -import hilog from '@ohos.hilog'; +import logger from '../utils/Logger'; @Component export struct NativeThreadsCallJSDemo { @@ -32,11 +32,12 @@ export struct NativeThreadsCallJSDemo { .width('40%') .fontSize(20) .onClick(()=> { + // native使用线程安全函数实现跨线程调用 entry.ThreadSafeTest((values: number) => { - values += 10 - hilog.info(0x0000, 'testTag', 'ThreadSafeTest js callback value =' + values) - this.value = values - return values + values += 10; + logger.info('ThreadSafeTest js callback value = ', values.toString()); + this.value = values; + return values; } ) }).margin(20) @@ -45,11 +46,12 @@ export struct NativeThreadsCallJSDemo { .width('40%') .fontSize(20) .onClick(()=> { + // native使用libuv实现跨线程调用 entry.UvWorkTest((values: number) => { - values += 10 - hilog.info(0x0000, 'testTag', 'UvWorkTest js callback value =' + values) - this.value = values - return values + values += 10; + logger.info('UvWorkTest js callback value = ', values.toString()); + this.value = values; + return values; } ) }).margin(10) diff --git a/code/Performance/PerformanceLibrary/feature/nativeThreadsCallJS/src/main/ets/utils/Logger.ets b/code/Performance/PerformanceLibrary/feature/nativeThreadsCallJS/src/main/ets/utils/Logger.ets new file mode 100644 index 000000000..c4ff45105 --- /dev/null +++ b/code/Performance/PerformanceLibrary/feature/nativeThreadsCallJS/src/main/ets/utils/Logger.ets @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import hilog from '@ohos.hilog'; + +class Logger { + // 日志对应的领域标识 + private domain: number = 0xF811; + // tag日志标识 + private prefix: string = '[Samples_PerformanceLibrary]'; + // 格式字符串,用于日志的格式化输出 + private format: string = '%{public}s, %{public}s'; + + constructor(prefix: string) { + this.prefix = prefix; + } + + debug(...args: string[]): void { + hilog.debug(this.domain, this.prefix, this.format, args); + } + + info(...args: string[]): void { + hilog.info(this.domain, this.prefix, this.format, args); + } + + warn(...args: string[]): void { + hilog.warn(this.domain, this.prefix, this.format, args); + } + + error(...args: string[]): void { + hilog.error(this.domain, this.prefix, this.format, args); + } +} + +export default new Logger('[Samples_Performance]'); \ No newline at end of file diff --git a/code/Performance/PerformanceLibrary/feature/nativeThreadsCallJS/src/test/LocalUnit.test.ets b/code/Performance/PerformanceLibrary/feature/nativeThreadsCallJS/src/test/LocalUnit.test.ets index f2bea0011..ee8288c88 100644 --- a/code/Performance/PerformanceLibrary/feature/nativeThreadsCallJS/src/test/LocalUnit.test.ets +++ b/code/Performance/PerformanceLibrary/feature/nativeThreadsCallJS/src/test/LocalUnit.test.ets @@ -36,13 +36,5 @@ export default function localUnitTest() { // Presets a clear action, which is performed after all test cases of the test suite end. // This API supports only one parameter: clear action function. }); - it('assertContain', 0, function () { - // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. - let a = 'abc'; - let b = 'b'; - // Defines a variety of assertion methods, which are used to declare expected boolean conditions. - expect(a).assertContain(b); - expect(a).assertEqual(a); - }); }); } \ No newline at end of file