Signed-off-by: zzz701 <lihaima1@huawei.com>
This commit is contained in:
zzz701 2024-01-11 14:46:37 +08:00
parent 4d74694693
commit 1994d5936b
4 changed files with 152 additions and 103 deletions

View File

@ -20,8 +20,8 @@
#include <thread>
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},

View File

@ -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)

View File

@ -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]');

View File

@ -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);
});
});
}