1e41f4b71Sopenharmony_ci# libuv 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ci## 简介 4e41f4b71Sopenharmony_ci 5e41f4b71Sopenharmony_ci[libuv](http://libuv.org/)是一个跨平台库,基于事件驱动来实现异步I/O,适用于网络编程和文件系统操作。它是Node.js的核心库之一,也被其他语言的开发者广泛使用。 6e41f4b71Sopenharmony_ci 7e41f4b71Sopenharmony_ci## 支持的能力 8e41f4b71Sopenharmony_ci 9e41f4b71Sopenharmony_ci[libuv](http://libuv.org/)实现了跨平台的基于事件驱动的异步I/O。 10e41f4b71Sopenharmony_ci 11e41f4b71Sopenharmony_ci支持标准库接口。 12e41f4b71Sopenharmony_ci 13e41f4b71Sopenharmony_ci## 引入libuv能力 14e41f4b71Sopenharmony_ci 15e41f4b71Sopenharmony_ci如果开发者需要使用libuv相关功能,首先请添加头文件: 16e41f4b71Sopenharmony_ci 17e41f4b71Sopenharmony_ci```c 18e41f4b71Sopenharmony_ci#include <uv.h> 19e41f4b71Sopenharmony_ci``` 20e41f4b71Sopenharmony_ci 21e41f4b71Sopenharmony_ci其次在CMakeLists.txt中添加以下动态链接库: 22e41f4b71Sopenharmony_ci 23e41f4b71Sopenharmony_ci``` 24e41f4b71Sopenharmony_cilibuv.so 25e41f4b71Sopenharmony_ci``` 26e41f4b71Sopenharmony_ci 27e41f4b71Sopenharmony_ci## 接口列表 28e41f4b71Sopenharmony_ci 29e41f4b71Sopenharmony_ci详见[libuv支持的API文档](http://docs.libuv.org/en/v1.x/api.html)。 30e41f4b71Sopenharmony_ci 31e41f4b71Sopenharmony_ci## OpenHarmony引入libuv的背景 32e41f4b71Sopenharmony_ci 33e41f4b71Sopenharmony_ci在OpenHarmony的早期版本中,为了兼容node的生态,将node的Node-API引入到系统中,方便node开发者快速接入OpenHarmony,扩展自己的js接口。同时引入了node的事件循环实现库——libuv。 34e41f4b71Sopenharmony_ci 35e41f4b71Sopenharmony_ci### 演进方向 36e41f4b71Sopenharmony_ci 37e41f4b71Sopenharmony_ci随着 OpenHarmony 的逐步完善,我们计划在未来的版本中,逐步将应用模型中的事件循环归一,并增强 OpenHarmony 自身的事件循环,以解决许多双 loop 机制下的调度问题,并为开发者提供更加完善的任务优先级、插队等与任务主循环交互的方法。 38e41f4b71Sopenharmony_ci 39e41f4b71Sopenharmony_ci开发者应尽可能避免在 `napi_get_uv_event_loop` 接口(已在API12中标记废弃)获取的应用主 loop 上使用 libuv 的 ndk 进行操作,因为这可能会带来各种问题,并给未来的兼容性变更带来大量的工作量。 40e41f4b71Sopenharmony_ci 41e41f4b71Sopenharmony_ci如果开发者希望跟主线程事件循环交互,比如插入任务等,应当使用[Node-API提供的接口](../../napi/napi-data-types-interfaces.md)。 42e41f4b71Sopenharmony_ci 43e41f4b71Sopenharmony_ciOpenHarmony 还将长期通过Node-API来为开发者提供和主线程交互及扩展js接口的能力,但会屏蔽实现层使用的事件循环。尽管我们在API12中给`napi_get_uv_event_loop`接口标记了废弃,但Node-API的主要功能接口将会长期维护,并保证与node的原生行为一致,来保证熟悉node.js的扩展机制的开发者方便地将自己的已有代码接入到OpenHarmony中来。 44e41f4b71Sopenharmony_ci 45e41f4b71Sopenharmony_ci如果您对 libuv 非常熟悉,并自信能够处理好所有的内存管理和多线程问题,您仍可以像使用原生 libuv 一样,自己启动线程,并在上面使用 libuv 完成自己的业务。在没有特殊版本要求的情况下,您不需要额外引入 libuv库到您的应用工程中。 46e41f4b71Sopenharmony_ci 47e41f4b71Sopenharmony_ci### 当前问题和解决方案 48e41f4b71Sopenharmony_ci 49e41f4b71Sopenharmony_ci根据现有机制,一个线程上只能存在一个事件循环,为了适配系统应用的主事件循环,在主线程上的js环境中,uvloop中的事件处理是由主事件循环监听其fd,触发一次`uv_run`来驱动的。因此部分依赖uvloop始终循环的功能无法生效。 50e41f4b71Sopenharmony_ci 51e41f4b71Sopenharmony_ci基于上述,比较常用的场景和解决方案有: 52e41f4b71Sopenharmony_ci 53e41f4b71Sopenharmony_ci#### 场景一、在JS主线程抛异步任务到工作线程执行,在主线程中执行JS代码处理返回结果 54e41f4b71Sopenharmony_ci 55e41f4b71Sopenharmony_ci**错误示例:** 56e41f4b71Sopenharmony_ci 57e41f4b71Sopenharmony_ci在native层直接通过调用`napi_get_uv_event_loop`接口获取系统loop,调用libuv NDK接口实现相关功能。 58e41f4b71Sopenharmony_ci 59e41f4b71Sopenharmony_ci```cpp 60e41f4b71Sopenharmony_ci#include "napi/native_api.h" 61e41f4b71Sopenharmony_ci#include "uv.h" 62e41f4b71Sopenharmony_ci#define LOG_DOMAIN 0X0202 63e41f4b71Sopenharmony_ci#define LOG_TAG "MyTag" 64e41f4b71Sopenharmony_ci#include <hilog/log.h> 65e41f4b71Sopenharmony_ci#include <thread> 66e41f4b71Sopenharmony_ci#include <sys/eventfd.h> 67e41f4b71Sopenharmony_ci#include <unistd.h> 68e41f4b71Sopenharmony_ci 69e41f4b71Sopenharmony_cistatic void execute(uv_work_t *work) { 70e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "ohos in execute"); 71e41f4b71Sopenharmony_ci} 72e41f4b71Sopenharmony_ci 73e41f4b71Sopenharmony_cistatic void complete(uv_work_t *work, int status) { 74e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "ohos in complete"); 75e41f4b71Sopenharmony_ci delete work; 76e41f4b71Sopenharmony_ci} 77e41f4b71Sopenharmony_cistatic napi_value Add(napi_env env, napi_callback_info info) 78e41f4b71Sopenharmony_ci{ 79e41f4b71Sopenharmony_ci napi_value work_name; 80e41f4b71Sopenharmony_ci uv_loop_s *loop = nullptr; 81e41f4b71Sopenharmony_ci /* 获取应用js主线程的uv_loop */ 82e41f4b71Sopenharmony_ci napi_get_uv_event_loop(env, &loop); 83e41f4b71Sopenharmony_ci uv_work_t *work = new uv_work_t; 84e41f4b71Sopenharmony_ci int ret = uv_queue_work(loop, work, execute, complete); 85e41f4b71Sopenharmony_ci if (ret != 0) { 86e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "delete work"); 87e41f4b71Sopenharmony_ci delete work; 88e41f4b71Sopenharmony_ci } 89e41f4b71Sopenharmony_ci return 0; 90e41f4b71Sopenharmony_ci} 91e41f4b71Sopenharmony_ci 92e41f4b71Sopenharmony_ciEXTERN_C_START 93e41f4b71Sopenharmony_cistatic napi_value Init(napi_env env, napi_value exports){ 94e41f4b71Sopenharmony_ci napi_property_descriptor desc[] = {{"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr}}; 95e41f4b71Sopenharmony_ci napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); 96e41f4b71Sopenharmony_ci return exports; 97e41f4b71Sopenharmony_ci} 98e41f4b71Sopenharmony_ciEXTERN_C_END 99e41f4b71Sopenharmony_ci 100e41f4b71Sopenharmony_cistatic napi_module demoModule = { 101e41f4b71Sopenharmony_ci .nm_version = 1, 102e41f4b71Sopenharmony_ci .nm_flags = 0, 103e41f4b71Sopenharmony_ci .nm_filename = nullptr, 104e41f4b71Sopenharmony_ci .nm_register_func = Init, 105e41f4b71Sopenharmony_ci .nm_modname = "entry", 106e41f4b71Sopenharmony_ci .nm_priv = ((void *)0), 107e41f4b71Sopenharmony_ci .reserved = {0}, 108e41f4b71Sopenharmony_ci}; 109e41f4b71Sopenharmony_ci 110e41f4b71Sopenharmony_ciextern "C" __attribute__((constructor)) void RegisterEntryModule(void){ 111e41f4b71Sopenharmony_ci napi_module_register(&demoModule); 112e41f4b71Sopenharmony_ci} 113e41f4b71Sopenharmony_ci``` 114e41f4b71Sopenharmony_ci 115e41f4b71Sopenharmony_ci**正确示例:** 116e41f4b71Sopenharmony_ci 117e41f4b71Sopenharmony_ci可通过`napi_create_async_work`、`napi_queue_async_work`搭配使用。 118e41f4b71Sopenharmony_ci 119e41f4b71Sopenharmony_ci```cpp 120e41f4b71Sopenharmony_ci#include "napi/native_api.h" 121e41f4b71Sopenharmony_ci#include "uv.h" 122e41f4b71Sopenharmony_ci#define LOG_DOMAIN 0X0202 123e41f4b71Sopenharmony_ci#define LOG_TAG "MyTag" 124e41f4b71Sopenharmony_ci#include <hilog/log.h> 125e41f4b71Sopenharmony_ci#include <thread> 126e41f4b71Sopenharmony_ci#include <sys/eventfd.h> 127e41f4b71Sopenharmony_ci#include <unistd.h> 128e41f4b71Sopenharmony_ciuv_loop_t *loop; 129e41f4b71Sopenharmony_cinapi_value jsCb; 130e41f4b71Sopenharmony_ciint fd = -1; 131e41f4b71Sopenharmony_ci 132e41f4b71Sopenharmony_cistatic napi_value Add(napi_env env, napi_callback_info info) 133e41f4b71Sopenharmony_ci{ 134e41f4b71Sopenharmony_ci napi_value work_name; 135e41f4b71Sopenharmony_ci napi_async_work work; 136e41f4b71Sopenharmony_ci napi_create_string_utf8(env, "ohos", NAPI_AUTO_LENGTH, &work_name); 137e41f4b71Sopenharmony_ci /* 第四个参数是异步线程的work任务,第五个参数为主线程的回调 */ 138e41f4b71Sopenharmony_ci napi_create_async_work(env, nullptr, work_name, [](napi_env env, void* data){ 139e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "ohos in execute"); 140e41f4b71Sopenharmony_ci }, [](napi_env env, napi_status status, void *data){ 141e41f4b71Sopenharmony_ci /* 不关心具体实现 */ 142e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "ohos in complete"); 143e41f4b71Sopenharmony_ci napi_delete_async_work(env, (napi_async_work)data); 144e41f4b71Sopenharmony_ci }, nullptr, &work); 145e41f4b71Sopenharmony_ci /* 通过napi_queue_async_work触发异步任务执行 */ 146e41f4b71Sopenharmony_ci napi_queue_async_work(env, work); 147e41f4b71Sopenharmony_ci return 0; 148e41f4b71Sopenharmony_ci} 149e41f4b71Sopenharmony_ci 150e41f4b71Sopenharmony_ciEXTERN_C_START 151e41f4b71Sopenharmony_cistatic napi_value Init(napi_env env, napi_value exports){ 152e41f4b71Sopenharmony_ci napi_property_descriptor desc[] = {{"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr}}; 153e41f4b71Sopenharmony_ci napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); 154e41f4b71Sopenharmony_ci return exports; 155e41f4b71Sopenharmony_ci} 156e41f4b71Sopenharmony_ciEXTERN_C_END 157e41f4b71Sopenharmony_ci 158e41f4b71Sopenharmony_cistatic napi_module demoModule = { 159e41f4b71Sopenharmony_ci .nm_version = 1, 160e41f4b71Sopenharmony_ci .nm_flags = 0, 161e41f4b71Sopenharmony_ci .nm_filename = nullptr, 162e41f4b71Sopenharmony_ci .nm_register_func = Init, 163e41f4b71Sopenharmony_ci .nm_modname = "entry", 164e41f4b71Sopenharmony_ci .nm_priv = ((void *)0), 165e41f4b71Sopenharmony_ci .reserved = {0}, 166e41f4b71Sopenharmony_ci}; 167e41f4b71Sopenharmony_ci 168e41f4b71Sopenharmony_ciextern "C" __attribute__((constructor)) void RegisterEntryModule(void){ 169e41f4b71Sopenharmony_ci napi_module_register(&demoModule); 170e41f4b71Sopenharmony_ci} 171e41f4b71Sopenharmony_ci``` 172e41f4b71Sopenharmony_ci 173e41f4b71Sopenharmony_ci#### 场景二、在native侧向应用主循环抛fd事件,接口无法生效 174e41f4b71Sopenharmony_ci 175e41f4b71Sopenharmony_ci由于应用主循环仅仅接收fd事件,在监听了uvloop中的backend_fd后,只有该fd事件被触发才会执行一次`uv_run`。这就意味着,在应用主循环中调用uv接口,如果不触发一次fd事件,`uv_run`将永远不会被执行,最后导致libuv的接口正常调用时不生效(仅当应用中没有触发uvloop中的fd事件时)。 176e41f4b71Sopenharmony_ci 177e41f4b71Sopenharmony_ci**错误示例:** 178e41f4b71Sopenharmony_ci 179e41f4b71Sopenharmony_ci我们以`uv_poll_start`接口举例,来说明在OpenHarmony中,我们像使用原生libuv一样调用`uv_poll_start`接口时无法生效的问题。 180e41f4b71Sopenharmony_ci 181e41f4b71Sopenharmony_ci```cpp 182e41f4b71Sopenharmony_ci#include "napi/native_api.h" 183e41f4b71Sopenharmony_ci#include "uv.h" 184e41f4b71Sopenharmony_ci#define LOG_DOMAIN 0X0202 185e41f4b71Sopenharmony_ci#define LOG_TAG "MyTag" 186e41f4b71Sopenharmony_ci#include <hilog/log.h> 187e41f4b71Sopenharmony_ci#include <thread> 188e41f4b71Sopenharmony_ci#include <sys/eventfd.h> 189e41f4b71Sopenharmony_ci#include <unistd.h> 190e41f4b71Sopenharmony_ciuv_loop_t *loop; 191e41f4b71Sopenharmony_cinapi_value jsCb; 192e41f4b71Sopenharmony_ciint fd = -1; 193e41f4b71Sopenharmony_civoid poll_handler(uv_poll_t* handle,int status, int events){ 194e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "ohos poll print"); 195e41f4b71Sopenharmony_ci} 196e41f4b71Sopenharmony_cistatic napi_value TestClose(napi_env env, napi_callback_info info){ 197e41f4b71Sopenharmony_ci std::thread::id this_id = std::this_thread::get_id(); 198e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "ohos thread id : %{public}ld\n", this_id); 199e41f4b71Sopenharmony_ci size_t argc = 1; 200e41f4b71Sopenharmony_ci napi_value workBname; 201e41f4b71Sopenharmony_ci 202e41f4b71Sopenharmony_ci napi_create_string_utf8(env, "test", NAPI_AUTO_LENGTH, &workBname); 203e41f4b71Sopenharmony_ci 204e41f4b71Sopenharmony_ci napi_get_cb_info(env, info, &argc, &jsCb, nullptr, nullptr); 205e41f4b71Sopenharmony_ci // 获取事件循环 206e41f4b71Sopenharmony_ci napi_get_uv_event_loop(env, &loop); 207e41f4b71Sopenharmony_ci // 创建一个eventfd 208e41f4b71Sopenharmony_ci fd = eventfd(0, 0); 209e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "fd is %{public}d\n",fd); 210e41f4b71Sopenharmony_ci uv_poll_t* poll_handle = new uv_poll_t; 211e41f4b71Sopenharmony_ci // 初始化一个poll句柄,并将其与eventfd关联 212e41f4b71Sopenharmony_ci uv_poll_init(loop, poll_handle, fd); 213e41f4b71Sopenharmony_ci // 开始监听poll事件 214e41f4b71Sopenharmony_ci uv_poll_start(poll_handle, UV_READABLE, poll_handler); 215e41f4b71Sopenharmony_ci // 创建一个新线程,向eventfd写入数据 216e41f4b71Sopenharmony_ci std::thread mythread([](){ 217e41f4b71Sopenharmony_ci for (int i = 0; i < 8; i++){ 218e41f4b71Sopenharmony_ci int value = 10; 219e41f4b71Sopenharmony_ci int ret = eventfd_write(fd, value); 220e41f4b71Sopenharmony_ci if (ret == -1){ 221e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "write failed!\n"); 222e41f4b71Sopenharmony_ci continue; 223e41f4b71Sopenharmony_ci } 224e41f4b71Sopenharmony_ci } 225e41f4b71Sopenharmony_ci }); 226e41f4b71Sopenharmony_ci mythread.detach(); 227e41f4b71Sopenharmony_ci return 0; 228e41f4b71Sopenharmony_ci} 229e41f4b71Sopenharmony_ciEXTERN_C_START 230e41f4b71Sopenharmony_cistatic napi_value Init(napi_env env, napi_value exports){ 231e41f4b71Sopenharmony_ci napi_property_descriptor desc[] = {{"testClose", nullptr, TestClose, nullptr, nullptr, nullptr, napi_default, nullptr}}; 232e41f4b71Sopenharmony_ci napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); 233e41f4b71Sopenharmony_ci return exports; 234e41f4b71Sopenharmony_ci} 235e41f4b71Sopenharmony_ciEXTERN_C_END 236e41f4b71Sopenharmony_ci 237e41f4b71Sopenharmony_cistatic napi_module demoModule = { 238e41f4b71Sopenharmony_ci .nm_version = 1, 239e41f4b71Sopenharmony_ci .nm_flags = 0, 240e41f4b71Sopenharmony_ci .nm_filename = nullptr, 241e41f4b71Sopenharmony_ci .nm_register_func = Init, 242e41f4b71Sopenharmony_ci .nm_modname = "entry", 243e41f4b71Sopenharmony_ci .nm_priv = ((void *)0), 244e41f4b71Sopenharmony_ci .reserved = {0}, 245e41f4b71Sopenharmony_ci}; 246e41f4b71Sopenharmony_ci 247e41f4b71Sopenharmony_ciextern "C" __attribute__((constructor)) void RegisterEntryModule(void){ 248e41f4b71Sopenharmony_ci napi_module_register(&demoModule); 249e41f4b71Sopenharmony_ci} 250e41f4b71Sopenharmony_ci``` 251e41f4b71Sopenharmony_ci 252e41f4b71Sopenharmony_ci在上述代码中,流程如下: 253e41f4b71Sopenharmony_ci 254e41f4b71Sopenharmony_ci1. 首先通过`napi_get_uv_event_loop`接口获取到应用主线程的uvloop。 255e41f4b71Sopenharmony_ci2. 然后创建一个eventfd。 256e41f4b71Sopenharmony_ci3. 初始化uv_poll_t,并启动该句柄使其生效,在eventfd可读时触发回调函数`poll_handler`。 257e41f4b71Sopenharmony_ci4. 新开一个线程,向eventfd里写入字符。 258e41f4b71Sopenharmony_ci 259e41f4b71Sopenharmony_ci执行上述代码,poll_handler并不能正常打印。这是由于应用主线程是靠fd驱动来执行`uv_run`的,而非以UV_RUN_DEFAULT模式来进行循环。尽管uvloop中的backend_fd已经被event_handler监听,但是当执行`uv_poll_start`的时候,fd并未通过`epoll_ctl`加入到backend_fd中被其监听,**而是在下一次`uv_run`中的`uv__io_poll`这个函数才会执行`epoll_ctl`函数。因此,如果应用进程中没有其他触发backend_fd事件的时候,libuv接口的正常使用可能不会达到开发者的预期。** 260e41f4b71Sopenharmony_ci 261e41f4b71Sopenharmony_ci**临时方案:** 262e41f4b71Sopenharmony_ci 263e41f4b71Sopenharmony_ci在当下的系统版本中,我们并不推荐开发者直接通过`napi_get_uv_event_loop`获取应用主线程的uvloop进行业务逻辑的开发。如果当前系统接口无法满足开发者的开发需求,确有必要使用libuv来实现业务功能,为了使libuv接口在主线程上生效,我们可以在调用类似*uv_xxx_start*后,执行一次`uv_async_send`的方式来主动触发应用主线程执行一次`uv_run`。这样可以保证该接口生效并正常执行。 264e41f4b71Sopenharmony_ci 265e41f4b71Sopenharmony_ci针对上述无法生效的代码示例,可以修改如下使其生效: 266e41f4b71Sopenharmony_ci 267e41f4b71Sopenharmony_ci```cpp 268e41f4b71Sopenharmony_ci#include "napi/native_api.h" 269e41f4b71Sopenharmony_ci#include "uv.h" 270e41f4b71Sopenharmony_ci#define LOG_DOMAIN 0x0202 271e41f4b71Sopenharmony_ci#define LOG_TAG "MyTag" 272e41f4b71Sopenharmony_ci#include <hilog/log.h> 273e41f4b71Sopenharmony_ci#include <thread> 274e41f4b71Sopenharmony_ci#include <sys/eventfd.h> 275e41f4b71Sopenharmony_ci#include <unistd.h> 276e41f4b71Sopenharmony_ciuv_loop_t *loop; 277e41f4b71Sopenharmony_cinapi_value jsCb; 278e41f4b71Sopenharmony_ciint fd = -1; 279e41f4b71Sopenharmony_civoid poll_handler(uv_poll_t* handle,int status, int events){ 280e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "ohos poll print"); 281e41f4b71Sopenharmony_ci} 282e41f4b71Sopenharmony_cistatic napi_value TestClose(napi_env env, napi_callback_info info){ 283e41f4b71Sopenharmony_ci std::thread::id this_id = std::this_thread::get_id(); 284e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "ohos thread id : %{public}ld\n", this_id); 285e41f4b71Sopenharmony_ci size_t argc = 1; 286e41f4b71Sopenharmony_ci napi_value workBName; 287e41f4b71Sopenharmony_ci 288e41f4b71Sopenharmony_ci napi_create_string_utf8(env, "test", NAPI_AUTO_LENGTH, &workBName); 289e41f4b71Sopenharmony_ci 290e41f4b71Sopenharmony_ci napi_get_cb_info(env, info, &argc, &jsCb, nullptr, nullptr); 291e41f4b71Sopenharmony_ci 292e41f4b71Sopenharmony_ci napi_get_uv_event_loop(env, &loop); 293e41f4b71Sopenharmony_ci 294e41f4b71Sopenharmony_ci fd = eventfd(0, 0); 295e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "fd is %{public}d\n",fd); 296e41f4b71Sopenharmony_ci uv_poll_t* poll_handle = new uv_poll_t; 297e41f4b71Sopenharmony_ci uv_poll_init(loop, poll_handle, fd); 298e41f4b71Sopenharmony_ci uv_poll_start(poll_handle, UV_READABLE, poll_handler); 299e41f4b71Sopenharmony_ci 300e41f4b71Sopenharmony_ci // 主动触发一次fd事件,让主线程执行一次uv_run 301e41f4b71Sopenharmony_ci uv_async_send(&loop->wq_async); 302e41f4b71Sopenharmony_ci 303e41f4b71Sopenharmony_ci std::thread mythread([](){ 304e41f4b71Sopenharmony_ci for (int i = 0; i < 8; i++){ 305e41f4b71Sopenharmony_ci int value = 10; 306e41f4b71Sopenharmony_ci int ret = eventfd_write(fd, value); 307e41f4b71Sopenharmony_ci if (ret == -1){ 308e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "write failed!\n"); 309e41f4b71Sopenharmony_ci continue; 310e41f4b71Sopenharmony_ci } 311e41f4b71Sopenharmony_ci } 312e41f4b71Sopenharmony_ci }); 313e41f4b71Sopenharmony_ci mythread.detach(); 314e41f4b71Sopenharmony_ci return 0; 315e41f4b71Sopenharmony_ci} 316e41f4b71Sopenharmony_ci 317e41f4b71Sopenharmony_ciEXTERN_C_START 318e41f4b71Sopenharmony_cistatic napi_value Init(napi_env env, napi_value exports){ 319e41f4b71Sopenharmony_ci napi_property_descriptor desc[] = {{"testClose", nullptr, TestClose, nullptr, nullptr, nullptr, napi_default, nullptr}}; 320e41f4b71Sopenharmony_ci napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); 321e41f4b71Sopenharmony_ci return exports; 322e41f4b71Sopenharmony_ci} 323e41f4b71Sopenharmony_ciEXTERN_C_END 324e41f4b71Sopenharmony_ci 325e41f4b71Sopenharmony_cistatic napi_module demoModule = { 326e41f4b71Sopenharmony_ci .nm_version = 1, 327e41f4b71Sopenharmony_ci .nm_flags = 0, 328e41f4b71Sopenharmony_ci .nm_filename = nullptr, 329e41f4b71Sopenharmony_ci .nm_register_func = Init, 330e41f4b71Sopenharmony_ci .nm_modname = "entry", 331e41f4b71Sopenharmony_ci .nm_priv = ((void *)0), 332e41f4b71Sopenharmony_ci .reserved = {0}, 333e41f4b71Sopenharmony_ci}; 334e41f4b71Sopenharmony_ci 335e41f4b71Sopenharmony_ciextern "C" __attribute__((constructor)) void RegisterEntryModule(void){ 336e41f4b71Sopenharmony_ci napi_module_register(&demoModule); 337e41f4b71Sopenharmony_ci} 338e41f4b71Sopenharmony_ci``` 339e41f4b71Sopenharmony_ci 340e41f4b71Sopenharmony_ci## libuv使用指导 341e41f4b71Sopenharmony_ci 342e41f4b71Sopenharmony_ci**重要:libuv NDK中所有依赖`uv_run`的接口在当前系统的应用主循环中无法及时生效,并且可能会导致卡顿掉帧的现象。因此不建议直接在JS主线程上使用libuv NDK接口,对于异步任务执行及与使用线程安全函数与主线程通信,开发者可以直接调用Node-API接口来实现相关功能。** 343e41f4b71Sopenharmony_ci 344e41f4b71Sopenharmony_ci### libuv接口与Node-API接口对应关系 345e41f4b71Sopenharmony_ci 346e41f4b71Sopenharmony_ci当前OpenHarmony提供了一些Node-API接口,可以替换libuv接口的使用。主要包括异步任务相关接口,线程安全的函数调用接口。 347e41f4b71Sopenharmony_ci 348e41f4b71Sopenharmony_ci#### 异步任务接口 349e41f4b71Sopenharmony_ci 350e41f4b71Sopenharmony_ci当开发者需要执行一个比较耗时的操作但又不希望阻塞主线程执行时,libuv提供了底层接口`uv_queue_work`帮助开发者在异步线程中执行耗时操作,然后将结果回调到主线程上进行处理。 351e41f4b71Sopenharmony_ci 352e41f4b71Sopenharmony_ci在Node-API中,通常可以通过[napi_async_work](../../napi/use-napi-asynchronous-task.md)相关函数来实现异步开发的功能。 353e41f4b71Sopenharmony_ci 354e41f4b71Sopenharmony_ci相关函数为: 355e41f4b71Sopenharmony_ci 356e41f4b71Sopenharmony_ci```cpp 357e41f4b71Sopenharmony_ci// 创建一个新的异步工作 358e41f4b71Sopenharmony_ci// env:指向当前环境的指针 359e41f4b71Sopenharmony_ci// async_resource:可选的资源对象,用于跟踪异步操作 360e41f4b71Sopenharmony_ci// async_resource_name:可选的字符串,用于描述异步资源 361e41f4b71Sopenharmony_ci// execute:一个回调函数,它将在一个新的线程中执行异步操作 362e41f4b71Sopenharmony_ci// complete:一个回调函数,它将在异步操作完成后被调用 363e41f4b71Sopenharmony_ci// data:用户定义的数据,它将被传递给execute和complete回调函数 364e41f4b71Sopenharmony_ci// result:指向新创建的异步工作的指针 365e41f4b71Sopenharmony_cinapi_status napi_create_async_work(napi_env env, 366e41f4b71Sopenharmony_ci napi_value async_resource, 367e41f4b71Sopenharmony_ci napi_value async_resource_name, 368e41f4b71Sopenharmony_ci napi_async_execute_callback execute, 369e41f4b71Sopenharmony_ci napi_async_complete_callback complete, 370e41f4b71Sopenharmony_ci void* data, 371e41f4b71Sopenharmony_ci napi_async_work* result); 372e41f4b71Sopenharmony_ci 373e41f4b71Sopenharmony_ci// 将异步工作添加到队列中 374e41f4b71Sopenharmony_ci// env:指向当前环境的指针 375e41f4b71Sopenharmony_ci// work:指向异步工作的指针 376e41f4b71Sopenharmony_cinapi_status napi_queue_async_work(napi_env env, napi_async_work work); 377e41f4b71Sopenharmony_ci 378e41f4b71Sopenharmony_ci// 删除异步工作 379e41f4b71Sopenharmony_ci// env:指向当前环境的指针 380e41f4b71Sopenharmony_ci// work:指向异步工作的指针 381e41f4b71Sopenharmony_cinapi_status napi_delete_async_work(napi_env env, napi_async_work work); 382e41f4b71Sopenharmony_ci``` 383e41f4b71Sopenharmony_ci 384e41f4b71Sopenharmony_ci#### 跨线程共享和调用的线程安全函数 385e41f4b71Sopenharmony_ci 386e41f4b71Sopenharmony_ci当开发者想传入某个回调函数到应用主线程上时,libuv的实现方式一般使用`uv_async_t`句柄用于线程间通信。 387e41f4b71Sopenharmony_ci 388e41f4b71Sopenharmony_ci相关函数包含: 389e41f4b71Sopenharmony_ci 390e41f4b71Sopenharmony_ci- uv_async_init() 391e41f4b71Sopenharmony_ci- uv_async_send() 392e41f4b71Sopenharmony_ci 393e41f4b71Sopenharmony_ciNode-API与之对应的接口为[napi_threadsafe_function](../../napi/use-napi-thread-safety.md)相关函数。 394e41f4b71Sopenharmony_ci 395e41f4b71Sopenharmony_ci相关函数: 396e41f4b71Sopenharmony_ci 397e41f4b71Sopenharmony_ci```cpp 398e41f4b71Sopenharmony_ci// 用于创建一个线程安全的函数,该函数可以在多个线程中调用,而不需要担心数据竞争或其他线程安全问题 399e41f4b71Sopenharmony_ci// env:指向NAPI环境的指针,用于创建和操作Javascript值 400e41f4b71Sopenharmony_ci// func:指向JavaScript函数的指针 401e41f4b71Sopenharmony_ci// resource_name:指向资源名称的指针,这个名称将用于日志和调试 402e41f4b71Sopenharmony_ci// max_queue_size:一个整数,表示队列的最大大小,当队列满时,新的调用将被丢弃 403e41f4b71Sopenharmony_ci// initial_thread_count:一个整数,表示初始线程数,这些线程将在创建函数时启动 404e41f4b71Sopenharmony_ci// context:指向上下文的指针,这个上下文将被传递给call_js_func函数 405e41f4b71Sopenharmony_ci// call_js_func:指向回调函数的指针,这个函数将在Javascript函数被调用时被调用 406e41f4b71Sopenharmony_ci// finalize:指向finalize函数的指针,这个函数将在线程安全函数被销毁时被调用 407e41f4b71Sopenharmony_ci// result:指向napi_threadsafe_function结构的指针,这个结构将被填充为新创建的线程安全函数 408e41f4b71Sopenharmony_cinapi_status napi_create_threadsafe_function(napi_env env, 409e41f4b71Sopenharmony_ci napi_value func, 410e41f4b71Sopenharmony_ci const char* resource_name, 411e41f4b71Sopenharmony_ci size_t max_queue_size, 412e41f4b71Sopenharmony_ci size_t initial_thread_count, 413e41f4b71Sopenharmony_ci void* context, 414e41f4b71Sopenharmony_ci napi_threadsafe_function_call_js call_js_func, 415e41f4b71Sopenharmony_ci napi_threadsafe_function_finalize finalize, 416e41f4b71Sopenharmony_ci napi_threadsafe_function* result); 417e41f4b71Sopenharmony_ci 418e41f4b71Sopenharmony_ci// 获取一个线程安全的函数 419e41f4b71Sopenharmony_ci// function:指向线程安全函数的指针 420e41f4b71Sopenharmony_cinapi_status napi_acquire_threadsafe_function(napi_threadsafe_function function); 421e41f4b71Sopenharmony_ci 422e41f4b71Sopenharmony_ci// 调用一个线程安全的函数 423e41f4b71Sopenharmony_ci// function:指向线程安全函数的指针 424e41f4b71Sopenharmony_ci// data:用户数据 425e41f4b71Sopenharmony_cinapi_status napi_call_threadsafe_function(napi_threadsafe_function function, void* data); 426e41f4b71Sopenharmony_ci 427e41f4b71Sopenharmony_ci// 释放一个线程安全的函数 428e41f4b71Sopenharmony_ci// function:指向线程安全函数的指针 429e41f4b71Sopenharmony_cinapi_status napi_release_threadsafe_function(napi_threadsafe_function function); 430e41f4b71Sopenharmony_ci 431e41f4b71Sopenharmony_ci``` 432e41f4b71Sopenharmony_ci 433e41f4b71Sopenharmony_ci除此之外,如果开发者需要libuv其他原生接口来实现业务功能,为了让开发者正确使用libuv提供的接口能力,避免因为错误使用而陷入到问题当中。在后续章节,我们将逐步介绍libuv的一些基本概念和OpenHarmony系统中常用函数的正确使用方法,它仅仅可以保证开发者使用libuv接口的时候不会出现应用进程崩溃等现象。另外,我们还统计了在当前应用主线程上可以正常使用的接口,以及无法在应用主线程上使用的接口。 434e41f4b71Sopenharmony_ci 435e41f4b71Sopenharmony_ci### 接口汇总说明 436e41f4b71Sopenharmony_ci 437e41f4b71Sopenharmony_ci| 接口类型 | 接口汇总 | 438e41f4b71Sopenharmony_ci| ---- | ---- | 439e41f4b71Sopenharmony_ci| [loop概念及相关接口](#libuv中的事件循环) | uv_loop_init | 440e41f4b71Sopenharmony_ci| [loop概念及相关接口](#libuv中的事件循环) | uv_loop_close | 441e41f4b71Sopenharmony_ci| [loop概念及相关接口](#libuv中的事件循环) | uv_default_loop | 442e41f4b71Sopenharmony_ci| [loop概念及相关接口](#libuv中的事件循环) | uv_run | 443e41f4b71Sopenharmony_ci| [loop概念及相关接口](#libuv中的事件循环) | uv_loop_alive | 444e41f4b71Sopenharmony_ci| [loop概念及相关接口](#libuv中的事件循环) | uv_stop | 445e41f4b71Sopenharmony_ci| [Handle概念及相关接口](#libuv中的handles和requests) | uv_poll\_\* | 446e41f4b71Sopenharmony_ci| [Handle概念及相关接口](#libuv中的handles和requests) | uv_timer\_\* | 447e41f4b71Sopenharmony_ci| [Handle概念及相关接口](#libuv中的handles和requests) | uv_async\_\* | 448e41f4b71Sopenharmony_ci| [Handle概念及相关接口](#libuv中的handles和requests) | uv_signal\_\* | 449e41f4b71Sopenharmony_ci| [Handle概念及相关接口](#libuv中的handles和requests) | uv_fs\_\* | 450e41f4b71Sopenharmony_ci| [Request概念及相关接口](#libuv中的handles和requests) | uv_random | 451e41f4b71Sopenharmony_ci| [Request概念及相关接口](#libuv中的handles和requests) | uv_getaddrinfo | 452e41f4b71Sopenharmony_ci| [Request概念及相关接口](#libuv中的handles和requests) | uv_getnameinfo | 453e41f4b71Sopenharmony_ci| [Request概念及相关接口](#libuv中的handles和requests) | uv_queue_work | 454e41f4b71Sopenharmony_ci| [线程间通信原理及相关接口](#线程间通信) | uv_async_init | 455e41f4b71Sopenharmony_ci| [线程间通信原理及相关接口](#线程间通信) | uv_async_send | 456e41f4b71Sopenharmony_ci| [线程池概念及相关接口](#线程池) | uv_queue_work | 457e41f4b71Sopenharmony_ci 458e41f4b71Sopenharmony_ci### 线程安全函数 459e41f4b71Sopenharmony_ci 460e41f4b71Sopenharmony_ci在libuv中,由于涉及到大量的异步任务,稍有不慎就会陷入到多线程问题中。在这里,我们对libuv中常用的线程安全函数和非线程安全函数做了汇总。若开发者在多线程编程中调用了非线程安全的函数,势必要对其进行加锁保护或者保证代码的正确运行时序。否则将陷入到crash问题中。 461e41f4b71Sopenharmony_ci 462e41f4b71Sopenharmony_ci线程安全函数: 463e41f4b71Sopenharmony_ci 464e41f4b71Sopenharmony_ci- uv_async_init():初始化异步句柄。 465e41f4b71Sopenharmony_ci- uv_async_send():向异步句柄发送信号,可以在任何线程中调用。 466e41f4b71Sopenharmony_ci- uv_thread_create():创建一个新线程并执行指定的函数,可以在任何线程中调用。 467e41f4b71Sopenharmony_ci- uv_fs\_\*():文件相关操作(uv\_fs\_\* 表示以uv\_fs\_开头的支持文件IO的系列函数)。 468e41f4b71Sopenharmony_ci- uv_poll\_\*():poll事件相关函数(uv\_poll\_\* 表示以uv\_poll\_开头的支持poll IO的系列函数)。 469e41f4b71Sopenharmony_ci- 锁相关的操作,如uv\_mutex\_lock()、uv\_mutex\_unlock()等等。 470e41f4b71Sopenharmony_ci 471e41f4b71Sopenharmony_ci**提示:所有形如uv_xxx_init的函数,即使它是以线程安全的方式实现的,但使用时要注意,避免多个线程同时调用uv_xxx_init,否则它依旧会引起多线程资源竞争的问题。最好的方式是在事件循环线程中调用该函数。** 472e41f4b71Sopenharmony_ci 473e41f4b71Sopenharmony_ci**注:uv_async_send函数被调用后,回调函数是被异步触发的。如果调用了多次uv_async_send,libuv只保证至少有一次回调会被执行。这就可能导致一旦对同一句柄触发了多次uv_async_send,libuv对回调的处理可能会违背开发者的预期。** 474e41f4b71Sopenharmony_ci 475e41f4b71Sopenharmony_ci非线程安全函数: 476e41f4b71Sopenharmony_ci 477e41f4b71Sopenharmony_ci- uv\_os\_unsetenv():删除环境变量 478e41f4b71Sopenharmony_ci- uv\_os\_setenv():设置环境变量 479e41f4b71Sopenharmony_ci- uv\_os\_getenv():获取环境变量 480e41f4b71Sopenharmony_ci- uv\_os\_environ():检索所有的环境变量 481e41f4b71Sopenharmony_ci- uv\_os\_tmpdir():获取临时目录 482e41f4b71Sopenharmony_ci- uv\_os\_homedir():获取家目录 483e41f4b71Sopenharmony_ci 484e41f4b71Sopenharmony_ci### libuv中的事件循环 485e41f4b71Sopenharmony_ci 486e41f4b71Sopenharmony_ci事件循环是libuv中最核心的一个概念,loop负责管理整个事件循环的所有资源,它贯穿于整个事件循环的生命周期。通常将`uv_run`所在的线程称为该事件循环的主线程。 487e41f4b71Sopenharmony_ci 488e41f4b71Sopenharmony_ci#### 事件循环运行的三种方式 489e41f4b71Sopenharmony_ci 490e41f4b71Sopenharmony_ci`UV_RUN_DEFAULT`:默认轮询方式,该模式将会一直运行下去,直到loop中没有活跃的句柄和请求。 491e41f4b71Sopenharmony_ci 492e41f4b71Sopenharmony_ci`UV_RUN_ONCE`:一次轮询模式,如果pending_queue中有回调函数,则执行,然后跳过`uv__io_poll`函数。此模式默认认为loop中一定有事件发生。 493e41f4b71Sopenharmony_ci 494e41f4b71Sopenharmony_ci`UV_RUN_NOWAIT`:非阻塞模式,该模式下不会执行pending_queue,而是直接执行一次I/O轮询(`uv__io_poll`)。 495e41f4b71Sopenharmony_ci 496e41f4b71Sopenharmony_ci#### 常用接口 497e41f4b71Sopenharmony_ci 498e41f4b71Sopenharmony_ci```cpp 499e41f4b71Sopenharmony_ciint uv_loop_init(uv_loop_t* loop); 500e41f4b71Sopenharmony_ci``` 501e41f4b71Sopenharmony_ci 502e41f4b71Sopenharmony_ci 对loop进行初始化。 503e41f4b71Sopenharmony_ci 504e41f4b71Sopenharmony_ci```cpp 505e41f4b71Sopenharmony_ciint uv_loop_close(uv_loop_t* loop); 506e41f4b71Sopenharmony_ci``` 507e41f4b71Sopenharmony_ci 508e41f4b71Sopenharmony_ci 关闭loop,该函数只有在loop中所有的句柄和请求都关闭后才能成功返回,否则将返回UV_EBUSY。 509e41f4b71Sopenharmony_ci 510e41f4b71Sopenharmony_ci```cpp 511e41f4b71Sopenharmony_ciuv_loop_t* uv_default_loop(void); 512e41f4b71Sopenharmony_ci``` 513e41f4b71Sopenharmony_ci 514e41f4b71Sopenharmony_ci 该函数创建一个进程级的loop。在OpenHarmony中,由于目前的应用主循环及其他js工作线程还存在着libuv的loop。因此我们不建议开发者使用该函数来创建loop并实现业务功能。在系统的双loop改造完成后,开发者可以根据业务要求来使用该接口。 515e41f4b71Sopenharmony_ci 516e41f4b71Sopenharmony_ci```cpp 517e41f4b71Sopenharmony_ciint uv_run(uv_loop_t* loop, uv_run_mode mode); 518e41f4b71Sopenharmony_ci``` 519e41f4b71Sopenharmony_ci 520e41f4b71Sopenharmony_ci 启动事件循环。运行模式可查看[事件循环运行的三种方式](#事件循环运行的三种方式)。 521e41f4b71Sopenharmony_ci 522e41f4b71Sopenharmony_ci```cpp 523e41f4b71Sopenharmony_ciint uv_loop_alive(uv_loop_t loop); 524e41f4b71Sopenharmony_ci``` 525e41f4b71Sopenharmony_ci 526e41f4b71Sopenharmony_ci 判断loop是否处于活跃状态。 527e41f4b71Sopenharmony_ci 528e41f4b71Sopenharmony_ci```cpp 529e41f4b71Sopenharmony_civoid uv_stop(uv_loop_t* loop); 530e41f4b71Sopenharmony_ci``` 531e41f4b71Sopenharmony_ci 532e41f4b71Sopenharmony_ci 该函数用来停止一个事件循环,在loop的下一次迭代中才会停止。如果该函数发生在I/O操作之前,将不会阻塞而是直接跳过`uv__io_poll`。 533e41f4b71Sopenharmony_ci 534e41f4b71Sopenharmony_ci**使用技巧**:在使用loop时,需要特别注意`uv_stop`函数的使用。开发者需要确保`uv_stop`前,通知与loop相关的所有线程的handle都关闭。参考代码如下: 535e41f4b71Sopenharmony_ci 536e41f4b71Sopenharmony_ci```cpp 537e41f4b71Sopenharmony_ciint stop_loop(uv_loop_t* loop) 538e41f4b71Sopenharmony_ci{ 539e41f4b71Sopenharmony_ci uv_stop(loop); 540e41f4b71Sopenharmony_ci auto const ensure_close = [](uv_handle_t* handle, void*) { 541e41f4b71Sopenharmony_ci if (uv_is_closing(handle)) { 542e41f4b71Sopenharmony_ci return; 543e41f4b71Sopenharmony_ci } else { 544e41f4b71Sopenharmony_ci uv_close(handle, nullptr); 545e41f4b71Sopenharmony_ci } 546e41f4b71Sopenharmony_ci }; 547e41f4b71Sopenharmony_ci // 遍历所有句柄,如果handle处于活跃状态,调用ensure_close。 548e41f4b71Sopenharmony_ci uv_walk(loop, ensure_close, nullptr); 549e41f4b71Sopenharmony_ci 550e41f4b71Sopenharmony_ci // 继续运行uv_run,直到loop中不存在活跃的句柄和请求为止。 551e41f4b71Sopenharmony_ci while(true) { 552e41f4b71Sopenharmony_ci if (uv_run(loop, UV_RUN_DEFAULT) == 0) { 553e41f4b71Sopenharmony_ci break; 554e41f4b71Sopenharmony_ci } 555e41f4b71Sopenharmony_ci } 556e41f4b71Sopenharmony_ci 557e41f4b71Sopenharmony_ci // 最后检查loop状态。 558e41f4b71Sopenharmony_ci if (uv_loop_alive(loop) != 0) { 559e41f4b71Sopenharmony_ci return -1; 560e41f4b71Sopenharmony_ci } 561e41f4b71Sopenharmony_ci return 0; 562e41f4b71Sopenharmony_ci} 563e41f4b71Sopenharmony_ci``` 564e41f4b71Sopenharmony_ci 565e41f4b71Sopenharmony_ci### libuv中的handles和requests 566e41f4b71Sopenharmony_ci 567e41f4b71Sopenharmony_cihandle表示一个持久性的对象,通常挂载到loop中对应的handle_queue队列上。如果handle处于活跃状态,每次`uv_run`都会处理handle中的回调函数。 568e41f4b71Sopenharmony_ci 569e41f4b71Sopenharmony_cirequest表示一个短暂性的请求,一个request只触发一次回调操作。 570e41f4b71Sopenharmony_ci 571e41f4b71Sopenharmony_ci下面是OpenHarmony系统中最常用的几个Handles和Requests: 572e41f4b71Sopenharmony_ci 573e41f4b71Sopenharmony_ci```cpp 574e41f4b71Sopenharmony_ci/* Handle Type */ 575e41f4b71Sopenharmony_citypedef struct uv_handle_s uv_handle_t; 576e41f4b71Sopenharmony_citypedef struct uv_timer_s uv_timer_t; 577e41f4b71Sopenharmony_citypedef struct uv_async_s uv_async_t; 578e41f4b71Sopenharmony_citypedef struct uv_signal_s uv_signal_t; 579e41f4b71Sopenharmony_ci 580e41f4b71Sopenharmony_ci/* Request Type */ 581e41f4b71Sopenharmony_citypedef struct uv_req_s uv_req_t; 582e41f4b71Sopenharmony_citypedef struct uv_work_s uv_work_t; 583e41f4b71Sopenharmony_citypedef struct uv_fs_s uv_fs_t; 584e41f4b71Sopenharmony_ci``` 585e41f4b71Sopenharmony_ci 586e41f4b71Sopenharmony_ci**注:在handles中,uv_xxx_t继承了uv_handle_t;在requests中,uv_work_t继承了uv_req_t。** 587e41f4b71Sopenharmony_ci 588e41f4b71Sopenharmony_ci对于libuv中的handles,对其有个正确的认识并管理好它的生命周期至关重要。handle作为一个长期存在于loop中的句柄,在使用中,开发者应遵循下面的原则: 589e41f4b71Sopenharmony_ci 590e41f4b71Sopenharmony_ci1. 句柄的初始化工作应在事件循环的线程中进行。 591e41f4b71Sopenharmony_ci2. 若由于业务问题,句柄需要在其他工作线程初始化,在使用之前用原子变量判断是否初始化完成。 592e41f4b71Sopenharmony_ci3. 句柄在确定后续不再使用后,调用`uv_close`将句柄从loop中摘除。 593e41f4b71Sopenharmony_ci 594e41f4b71Sopenharmony_ci在这里,需要特别说明一下`uv_close`的使用方法。`uv_close`被用来关闭一个handle,但是它是异步地关闭handle。函数原型为: 595e41f4b71Sopenharmony_ci 596e41f4b71Sopenharmony_ci```cpp 597e41f4b71Sopenharmony_civoid uv_close(uv_handle_t* handle, uv_close_cb close_cb) 598e41f4b71Sopenharmony_ci``` 599e41f4b71Sopenharmony_ci 600e41f4b71Sopenharmony_ci handle:要关闭的句柄。 601e41f4b71Sopenharmony_ci close_cb:处理该句柄的函数,用来进行内存管理等操作。 602e41f4b71Sopenharmony_ci 603e41f4b71Sopenharmony_ci`uv_close`调用后,它首先将要关闭的handle挂载到loop中的closing_handles队列上,然后等待loop所在线程运行`uv__run_closing_handles`函数。最后回调函数close_cb将会在loop的下一次迭代中执行。因此,释放内存等操作应该在close_cb中进行。并且这种异步的关闭操作会带来多线程上的问题,开发者需要谨慎处理`uv_close`的时序问题,并且保证在close_cb执行之前Handles的生命周期。这是一篇在系统中存在的一些典型代码示例,可供开发者参考。 604e41f4b71Sopenharmony_ci 605e41f4b71Sopenharmony_ci**Tips**:在[libuv官方文档](http://libuv.org/)中,有个经验法则需要在此提示一下。原文翻译:如果 uv_foo_t 类型的句柄具有 `uv_foo_start()` 函数,则从调用该函数的那一刻起,它就处于活动状态。 同样,`uv_foo_stop()`再次停用句柄。 606e41f4b71Sopenharmony_ci 607e41f4b71Sopenharmony_ci而对于libuv中的requests,开发者需要确保一点,通过动态申请的request,在loop所在线程的回调函数中释放它即可。用uv_work_t举例,代码可参考如下: 608e41f4b71Sopenharmony_ci 609e41f4b71Sopenharmony_ci```cpp 610e41f4b71Sopenharmony_ciuv_work_t* work = new uv_work_t; 611e41f4b71Sopenharmony_ciuv_queue_work(loop, work, [](uv_work_t* req) { 612e41f4b71Sopenharmony_ci // 异步操作 613e41f4b71Sopenharmony_ci}, [](uv_work_t* req, int status) { 614e41f4b71Sopenharmony_ci // 回调操作 615e41f4b71Sopenharmony_ci delete req; 616e41f4b71Sopenharmony_ci}); 617e41f4b71Sopenharmony_ci``` 618e41f4b71Sopenharmony_ci 619e41f4b71Sopenharmony_ci此外,使用`uv_queue_work`需要注意如下几点: 620e41f4b71Sopenharmony_ci 621e41f4b71Sopenharmony_ci1. libuv中`uv_queue_work`的工作流程为:将`work_cb`挂在线程池中执行,然后将`after_work_cb`挂在回调队列wq中,然后触发一次fd事件;loop所在线程接收到fd事件,便会执行对应的after_work_cb。`uv_queue_work`调用完后,并不代表其中的任何一个任务执行完,仅代表将work_cb插入到异步线程池的任务队列中。 622e41f4b71Sopenharmony_ci2. `uv_queue_work`仅限于在loop所在的线程中调用,这样不会有多线程安全问题。不建议使用如下用法:A线程获取到B线程的loop,并通过`uv_queue_work`的方式,把回调放在B线程中执行。 623e41f4b71Sopenharmony_ci3. 为了避免低效的异步任务提交,请不要使用将work_cb实现为空任务,并将任务在after_work_cb中执行的方式调用`uv_queue_work`提交异步任务,请使用`napi_send_event`接口。 624e41f4b71Sopenharmony_ci 625e41f4b71Sopenharmony_ci`napi_send_event`函数的声明为: 626e41f4b71Sopenharmony_ci 627e41f4b71Sopenharmony_ci```cpp 628e41f4b71Sopenharmony_cinapi_status napi_send_event(napi_env env, const std::function<void()> cb, napi_event_priority priority); 629e41f4b71Sopenharmony_ci``` 630e41f4b71Sopenharmony_ci 631e41f4b71Sopenharmony_ci#### libuv timer使用规范 632e41f4b71Sopenharmony_ci 633e41f4b71Sopenharmony_ci使用libuv timer需要遵守如下约定: 634e41f4b71Sopenharmony_ci 635e41f4b71Sopenharmony_ci1. 请不要在多个线程中使用libuv的接口(uv_timer_start、uv_timer_stop和uv_timer_again)同时操作同一个loop的timer heap,否则将导致崩溃,如果想要使用libuv的接口操作定时器,请**保持在与当前env绑定的loop所在线程上操作**; 636e41f4b71Sopenharmony_ci2. 如因业务需求往指定线程抛定时器,请使用`uv_async_send`线程安全函数实现。 637e41f4b71Sopenharmony_ci 638e41f4b71Sopenharmony_ci##### 错误使用timer示例 639e41f4b71Sopenharmony_ci 640e41f4b71Sopenharmony_ci以下错误示例中,由于在多个线程操作同一个loop的timer heap,崩溃率极高。 641e41f4b71Sopenharmony_ci 642e41f4b71Sopenharmony_ciArkTS侧: 643e41f4b71Sopenharmony_ci 644e41f4b71Sopenharmony_ci```typescript 645e41f4b71Sopenharmony_ciimport { hilog } from '@kit.PerformanceAnalysisKit'; 646e41f4b71Sopenharmony_ciimport testNapi from 'libentry.so' 647e41f4b71Sopenharmony_ci 648e41f4b71Sopenharmony_cifunction waitforRunner(): number { 649e41f4b71Sopenharmony_ci "use concurrent" 650e41f4b71Sopenharmony_ci hilog.info(0xff, "testTag", "executed"); 651e41f4b71Sopenharmony_ci return 0; 652e41f4b71Sopenharmony_ci} 653e41f4b71Sopenharmony_ci 654e41f4b71Sopenharmony_ci@Entry 655e41f4b71Sopenharmony_ci@Component 656e41f4b71Sopenharmony_cistruct Index { 657e41f4b71Sopenharmony_ci build() { 658e41f4b71Sopenharmony_ci Row() { 659e41f4b71Sopenharmony_ci Column() { 660e41f4b71Sopenharmony_ci Button("TimerTest") 661e41f4b71Sopenharmony_ci .width('40%') 662e41f4b71Sopenharmony_ci .fontSize('14fp') 663e41f4b71Sopenharmony_ci .onClick(() => { 664e41f4b71Sopenharmony_ci let i: number = 20; 665e41f4b71Sopenharmony_ci while (i--) { 666e41f4b71Sopenharmony_ci setTimeout(waitforRunner, 200); 667e41f4b71Sopenharmony_ci testNapi.testTimer(); 668e41f4b71Sopenharmony_ci } 669e41f4b71Sopenharmony_ci }).margin(20) 670e41f4b71Sopenharmony_ci }.width('100%') 671e41f4b71Sopenharmony_ci }.height('100%') 672e41f4b71Sopenharmony_ci } 673e41f4b71Sopenharmony_ci} 674e41f4b71Sopenharmony_ci``` 675e41f4b71Sopenharmony_ci 676e41f4b71Sopenharmony_ciNative C++侧: 677e41f4b71Sopenharmony_ci 678e41f4b71Sopenharmony_ci```cpp 679e41f4b71Sopenharmony_ci#include <napi/native_api.h> 680e41f4b71Sopenharmony_ci#include <uv.h> 681e41f4b71Sopenharmony_ci#define LOG_DOMAIN 0x0202 682e41f4b71Sopenharmony_ci#define LOG_TAG "MyTag" 683e41f4b71Sopenharmony_ci#include "hilog/log.h" 684e41f4b71Sopenharmony_ci#include <thread> 685e41f4b71Sopenharmony_ci#include <unistd.h> 686e41f4b71Sopenharmony_ci 687e41f4b71Sopenharmony_cistatic napi_value TestTimer(napi_env env, napi_callback_info info) { 688e41f4b71Sopenharmony_ci uv_loop_t* loop = nullptr; 689e41f4b71Sopenharmony_ci uv_timer_t* timer = new uv_timer_t; 690e41f4b71Sopenharmony_ci 691e41f4b71Sopenharmony_ci napi_get_uv_event_loop(env, &loop); 692e41f4b71Sopenharmony_ci uv_timer_init(loop, timer); 693e41f4b71Sopenharmony_ci std::thread t1([&loop, &timer](){ 694e41f4b71Sopenharmony_ci uv_timer_start(timer, [](uv_timer_t* timer){ 695e41f4b71Sopenharmony_ci uv_timer_stop(timer); 696e41f4b71Sopenharmony_ci }, 1000, 0); 697e41f4b71Sopenharmony_ci }); 698e41f4b71Sopenharmony_ci 699e41f4b71Sopenharmony_ci t1.detach(); 700e41f4b71Sopenharmony_ci return 0; 701e41f4b71Sopenharmony_ci} 702e41f4b71Sopenharmony_ci 703e41f4b71Sopenharmony_ciEXTERN_C_START 704e41f4b71Sopenharmony_cistatic napi_value Init(napi_env env, napi_value exports) { 705e41f4b71Sopenharmony_ci napi_property_descriptor desc[] = { 706e41f4b71Sopenharmony_ci {"testTimer", nullptr, TestTimer, nullptr, nullptr, nullptr, napi_default, nullptr}, 707e41f4b71Sopenharmony_ci }; 708e41f4b71Sopenharmony_ci napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); 709e41f4b71Sopenharmony_ci return exports; 710e41f4b71Sopenharmony_ci} 711e41f4b71Sopenharmony_ciEXTERN_C_END 712e41f4b71Sopenharmony_ci 713e41f4b71Sopenharmony_cistatic napi_module demoModule = { 714e41f4b71Sopenharmony_ci .nm_version = 1, 715e41f4b71Sopenharmony_ci .nm_flags = 0, 716e41f4b71Sopenharmony_ci .nm_filename = nullptr, 717e41f4b71Sopenharmony_ci .nm_register_func = Init, 718e41f4b71Sopenharmony_ci .nm_modname = "entry", 719e41f4b71Sopenharmony_ci .nm_priv = ((void *)0), 720e41f4b71Sopenharmony_ci .reserved = {0}, 721e41f4b71Sopenharmony_ci}; 722e41f4b71Sopenharmony_ci 723e41f4b71Sopenharmony_ciextern "C" __attribute__((constructor)) void RegisterEntryModule(void) { 724e41f4b71Sopenharmony_ci napi_module_register(&demoModule); 725e41f4b71Sopenharmony_ci} 726e41f4b71Sopenharmony_ci``` 727e41f4b71Sopenharmony_ci 728e41f4b71Sopenharmony_ci在index.d.ts增加如下代码: 729e41f4b71Sopenharmony_ci 730e41f4b71Sopenharmony_ci```typescript 731e41f4b71Sopenharmony_ciexport const testTimer:() => number; 732e41f4b71Sopenharmony_ci``` 733e41f4b71Sopenharmony_ci 734e41f4b71Sopenharmony_ci##### 正确使用timer示例 735e41f4b71Sopenharmony_ci 736e41f4b71Sopenharmony_ci**场景一:** 在上述场景中,需保证在native主线程上进行timer的相关操作。将上述TestTimer函数的代码做如下修改,便可以避免崩溃发生。 737e41f4b71Sopenharmony_ci 738e41f4b71Sopenharmony_ci```cpp 739e41f4b71Sopenharmony_cistatic napi_value TestTimer(napi_env env, napi_callback_info info) { 740e41f4b71Sopenharmony_ci uv_loop_t* loop = nullptr; 741e41f4b71Sopenharmony_ci uv_timer_t* timer = new uv_timer_t; 742e41f4b71Sopenharmony_ci 743e41f4b71Sopenharmony_ci napi_get_uv_event_loop(env, &loop); 744e41f4b71Sopenharmony_ci uv_timer_init(loop, timer); 745e41f4b71Sopenharmony_ci uv_timer_start(timer, [](uv_timer_t* timer){ 746e41f4b71Sopenharmony_ci uv_timer_stop(timer); 747e41f4b71Sopenharmony_ci }, 1000, 0); 748e41f4b71Sopenharmony_ci 749e41f4b71Sopenharmony_ci return 0; 750e41f4b71Sopenharmony_ci} 751e41f4b71Sopenharmony_ci``` 752e41f4b71Sopenharmony_ci 753e41f4b71Sopenharmony_ci**场景二:** 如果需要在指定的子线程抛定时器,请使用线程安全函数`uv_async_send`实现。 754e41f4b71Sopenharmony_ci 755e41f4b71Sopenharmony_ciArkTS测: 756e41f4b71Sopenharmony_ci 757e41f4b71Sopenharmony_ci```typescript 758e41f4b71Sopenharmony_ciimport { hilog } from '@kit.PerformanceAnalysisKit'; 759e41f4b71Sopenharmony_ciimport testNapi from 'libentry.so' 760e41f4b71Sopenharmony_ci 761e41f4b71Sopenharmony_cifunction waitforRunner(): number { 762e41f4b71Sopenharmony_ci "use concurrent" 763e41f4b71Sopenharmony_ci hilog.info(0xff, "testTag", "executed"); 764e41f4b71Sopenharmony_ci return 0; 765e41f4b71Sopenharmony_ci} 766e41f4b71Sopenharmony_ci 767e41f4b71Sopenharmony_ci@Entry 768e41f4b71Sopenharmony_ci@Component 769e41f4b71Sopenharmony_cistruct Index { 770e41f4b71Sopenharmony_ci build() { 771e41f4b71Sopenharmony_ci Row() { 772e41f4b71Sopenharmony_ci Column() { 773e41f4b71Sopenharmony_ci Button("TestTimerAsync") 774e41f4b71Sopenharmony_ci .width('40%') 775e41f4b71Sopenharmony_ci .fontSize('14fp') 776e41f4b71Sopenharmony_ci .onClick(() => { 777e41f4b71Sopenharmony_ci testNapi.testTimerAsync(); // 初始化async句柄 778e41f4b71Sopenharmony_ci }).margin(20) 779e41f4b71Sopenharmony_ci 780e41f4b71Sopenharmony_ci Button("TestTimerAsyncSend") 781e41f4b71Sopenharmony_ci .width('40%') 782e41f4b71Sopenharmony_ci .fontSize('14fp') 783e41f4b71Sopenharmony_ci .onClick(() => { 784e41f4b71Sopenharmony_ci testNapi.testTimerAsyncSend(); // 子线程调用uv_async_send执行timer_cb 785e41f4b71Sopenharmony_ci }).margin(20) 786e41f4b71Sopenharmony_ci }.width('100%') 787e41f4b71Sopenharmony_ci }.height('100%') 788e41f4b71Sopenharmony_ci } 789e41f4b71Sopenharmony_ci} 790e41f4b71Sopenharmony_ci``` 791e41f4b71Sopenharmony_ci 792e41f4b71Sopenharmony_ciNative C++测: 793e41f4b71Sopenharmony_ci 794e41f4b71Sopenharmony_ci```c++ 795e41f4b71Sopenharmony_ci#include <napi/native_api.h> 796e41f4b71Sopenharmony_ci#include <uv.h> 797e41f4b71Sopenharmony_ci#define LOG_DOMAIN 0x0202 798e41f4b71Sopenharmony_ci#define LOG_TAG "MyTag" 799e41f4b71Sopenharmony_ci#include "hilog/log.h" 800e41f4b71Sopenharmony_ci#include <thread> 801e41f4b71Sopenharmony_ci#include <unistd.h> 802e41f4b71Sopenharmony_ciuv_async_t* async = new uv_async_t; 803e41f4b71Sopenharmony_ci 804e41f4b71Sopenharmony_ci// 执行创建定时器操作 805e41f4b71Sopenharmony_civoid timer_cb(uv_async_t* handle) { 806e41f4b71Sopenharmony_ci auto loop = handle->loop; 807e41f4b71Sopenharmony_ci uv_timer_t* timer = new uv_timer_t; 808e41f4b71Sopenharmony_ci uv_timer_init(loop, timer); 809e41f4b71Sopenharmony_ci 810e41f4b71Sopenharmony_ci uv_timer_start(timer, [](uv_timer_t* timer){ 811e41f4b71Sopenharmony_ci uv_timer_stop(timer); 812e41f4b71Sopenharmony_ci }, 1000, 0); 813e41f4b71Sopenharmony_ci} 814e41f4b71Sopenharmony_ci 815e41f4b71Sopenharmony_ci// 初始化async句柄,绑定对应的回调函数 816e41f4b71Sopenharmony_cistatic napi_value TestTimerAsync(napi_env env, napi_callback_info info) { 817e41f4b71Sopenharmony_ci uv_loop_t* loop = nullptr; 818e41f4b71Sopenharmony_ci napi_get_uv_event_loop(env, &loop); 819e41f4b71Sopenharmony_ci uv_async_init(loop, async, timer_cb); 820e41f4b71Sopenharmony_ci return 0; 821e41f4b71Sopenharmony_ci} 822e41f4b71Sopenharmony_ci 823e41f4b71Sopenharmony_cistatic napi_value TestTimerAsyncSend(napi_env env, napi_callback_info info) { 824e41f4b71Sopenharmony_ci std::thread t([](){ 825e41f4b71Sopenharmony_ci uv_async_send(async); // 在任意子线程中调用uv_async_send,通知主线程调用与async绑定的timer_cb 826e41f4b71Sopenharmony_ci }); 827e41f4b71Sopenharmony_ci t.detach(); 828e41f4b71Sopenharmony_ci return 0; 829e41f4b71Sopenharmony_ci} 830e41f4b71Sopenharmony_ci 831e41f4b71Sopenharmony_ciEXTERN_C_START 832e41f4b71Sopenharmony_cistatic napi_value Init(napi_env env, napi_value exports) { 833e41f4b71Sopenharmony_ci napi_property_descriptor desc[] = { 834e41f4b71Sopenharmony_ci {"testTimerAsync", nullptr, TestTimerAsync, nullptr, nullptr, nullptr, napi_default, nullptr}, 835e41f4b71Sopenharmony_ci {"testTimerAsyncSend", nullptr, TestTimerAsyncSend, nullptr, nullptr, nullptr, napi_default, nullptr}, 836e41f4b71Sopenharmony_ci }; 837e41f4b71Sopenharmony_ci napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); 838e41f4b71Sopenharmony_ci return exports; 839e41f4b71Sopenharmony_ci} 840e41f4b71Sopenharmony_ciEXTERN_C_END 841e41f4b71Sopenharmony_ci 842e41f4b71Sopenharmony_cistatic napi_module demoModule = { 843e41f4b71Sopenharmony_ci .nm_version = 1, 844e41f4b71Sopenharmony_ci .nm_flags = 0, 845e41f4b71Sopenharmony_ci .nm_filename = nullptr, 846e41f4b71Sopenharmony_ci .nm_register_func = Init, 847e41f4b71Sopenharmony_ci .nm_modname = "entry", 848e41f4b71Sopenharmony_ci .nm_priv = ((void *)0), 849e41f4b71Sopenharmony_ci .reserved = {0}, 850e41f4b71Sopenharmony_ci}; 851e41f4b71Sopenharmony_ci 852e41f4b71Sopenharmony_ciextern "C" __attribute__((constructor)) void RegisterEntryModule(void) { 853e41f4b71Sopenharmony_ci napi_module_register(&demoModule); 854e41f4b71Sopenharmony_ci} 855e41f4b71Sopenharmony_ci``` 856e41f4b71Sopenharmony_ci 857e41f4b71Sopenharmony_ci### 线程间通信 858e41f4b71Sopenharmony_ci 859e41f4b71Sopenharmony_ci上面简单介绍了一些libuv中的基本概念,在这里我们将着重介绍libuv中的线程间通信。 860e41f4b71Sopenharmony_ci 861e41f4b71Sopenharmony_cilibuv的线程间通信是通过uv_async_t句柄来进行的,相关函数如下: 862e41f4b71Sopenharmony_ci 863e41f4b71Sopenharmony_ci```cpp 864e41f4b71Sopenharmony_ciint uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) 865e41f4b71Sopenharmony_ci``` 866e41f4b71Sopenharmony_ci 867e41f4b71Sopenharmony_ci loop:事件循环loop。 868e41f4b71Sopenharmony_ci 869e41f4b71Sopenharmony_ci handle:线程间通信句柄。 870e41f4b71Sopenharmony_ci 871e41f4b71Sopenharmony_ci async_cb:回调函数。 872e41f4b71Sopenharmony_ci 873e41f4b71Sopenharmony_ci 返回:成功,返回0。失败,返回错误码。 874e41f4b71Sopenharmony_ci 875e41f4b71Sopenharmony_ci```cpp 876e41f4b71Sopenharmony_ciint uv_async_send(uv_async_t* handle) 877e41f4b71Sopenharmony_ci``` 878e41f4b71Sopenharmony_ci 879e41f4b71Sopenharmony_ci handle:线程间通信句柄。 880e41f4b71Sopenharmony_ci 881e41f4b71Sopenharmony_ci 返回:成功,返回0。失败,返回错误码。 882e41f4b71Sopenharmony_ci> 说明 883e41f4b71Sopenharmony_ci> 884e41f4b71Sopenharmony_ci> 1. uv_async_t从调用`uv_async_init`开始后就一直处于活跃状态,除非用`uv_close`将其关闭。 885e41f4b71Sopenharmony_ci> 886e41f4b71Sopenharmony_ci> 2. uv_async_t的执行顺序严格按照`uv_async_init`的顺序,而非通过`uv_async_send`的顺序来执行的。因此按照初始化的顺序来管理好时序问题是必要的。 887e41f4b71Sopenharmony_ci 888e41f4b71Sopenharmony_ci 889e41f4b71Sopenharmony_ci 890e41f4b71Sopenharmony_ci示例代码: 891e41f4b71Sopenharmony_ci 892e41f4b71Sopenharmony_ci```cpp 893e41f4b71Sopenharmony_ci#include <bits/stdc++.h> 894e41f4b71Sopenharmony_ci#include "uv.h" 895e41f4b71Sopenharmony_ci 896e41f4b71Sopenharmony_ciuv_loop_t* loop = nullptr; 897e41f4b71Sopenharmony_ciuv_async_t* async = nullptr; 898e41f4b71Sopenharmony_civoid async_handler(uv_async_t* handle) 899e41f4b71Sopenharmony_ci{ 900e41f4b71Sopenharmony_ci printf("ohos async print\n"); 901e41f4b71Sopenharmony_ci} 902e41f4b71Sopenharmony_ci 903e41f4b71Sopenharmony_ciint main() 904e41f4b71Sopenharmony_ci{ 905e41f4b71Sopenharmony_ci loop = uv_default_loop(); 906e41f4b71Sopenharmony_ci async = new uv_async_t; 907e41f4b71Sopenharmony_ci uv_async_init(loop, async, async_handler); 908e41f4b71Sopenharmony_ci std::thread subThread([]() { 909e41f4b71Sopenharmony_ci for (int i = 0; i < 10; i++) { 910e41f4b71Sopenharmony_ci usleep(100); 911e41f4b71Sopenharmony_ci printf("%dth: subThread triggered\n", i); 912e41f4b71Sopenharmony_ci uv_async_send(async); 913e41f4b71Sopenharmony_ci } 914e41f4b71Sopenharmony_ci // 调用uv_close关闭async,在主循环中释放内存。 915e41f4b71Sopenharmony_ci uv_close((uv_handle_t*)async, [](uv_handle_t* handle) { 916e41f4b71Sopenharmony_ci printf("delete async\n"); 917e41f4b71Sopenharmony_ci delete (uv_async_t*)handle; 918e41f4b71Sopenharmony_ci }); 919e41f4b71Sopenharmony_ci uv_stop(loop); 920e41f4b71Sopenharmony_ci }); 921e41f4b71Sopenharmony_ci subThread.detach(); 922e41f4b71Sopenharmony_ci return uv_run(loop, UV_RUN_DEFAULT); 923e41f4b71Sopenharmony_ci} 924e41f4b71Sopenharmony_ci``` 925e41f4b71Sopenharmony_ci 926e41f4b71Sopenharmony_ci该示例代码仅仅描述了一个简单的场景,步骤如下: 927e41f4b71Sopenharmony_ci 928e41f4b71Sopenharmony_ci1. 在主线程中初始化async句柄 929e41f4b71Sopenharmony_ci2. 新建一个子线程,在里面每隔100毫秒触发一次`uv_async_send`。10次以后调用`uv_close`关闭async句柄。 930e41f4b71Sopenharmony_ci3. 在主线程运行事件循环。 931e41f4b71Sopenharmony_ci 932e41f4b71Sopenharmony_ci可以看到,每触发一次,主线程都会执行一次回调函数。 933e41f4b71Sopenharmony_ci 934e41f4b71Sopenharmony_ci``` 935e41f4b71Sopenharmony_ci0th:subThread triggered 936e41f4b71Sopenharmony_ciohos async print 937e41f4b71Sopenharmony_ci1th:subThread triggered 938e41f4b71Sopenharmony_ciohos async print 939e41f4b71Sopenharmony_ci2th:subThread triggered 940e41f4b71Sopenharmony_ciohos async print 941e41f4b71Sopenharmony_ci3th:subThread triggered 942e41f4b71Sopenharmony_ciohos async print 943e41f4b71Sopenharmony_ci4th:subThread triggered 944e41f4b71Sopenharmony_ciohos async print 945e41f4b71Sopenharmony_ci5th:subThread triggered 946e41f4b71Sopenharmony_ciohos async print 947e41f4b71Sopenharmony_ci6th:subThread triggered 948e41f4b71Sopenharmony_ciohos async print 949e41f4b71Sopenharmony_ci7th:subThread triggered 950e41f4b71Sopenharmony_ciohos async print 951e41f4b71Sopenharmony_ci8th:subThread triggered 952e41f4b71Sopenharmony_ciohos async print 953e41f4b71Sopenharmony_ci9th:subThread triggered 954e41f4b71Sopenharmony_cidelete async 955e41f4b71Sopenharmony_ci``` 956e41f4b71Sopenharmony_ci 957e41f4b71Sopenharmony_ci### 线程池 958e41f4b71Sopenharmony_ci 959e41f4b71Sopenharmony_ci线程池是libuv的一个核心功能,libuv中的线程池是通过uv_loop_t中的成员变量wq_async来控制工作线程与主线程的通信。核心函数如下: 960e41f4b71Sopenharmony_ci 961e41f4b71Sopenharmony_ci```cpp 962e41f4b71Sopenharmony_ciint uv_queue_work(uv_loop_t* loop, 963e41f4b71Sopenharmony_ci uv_work_t* req, 964e41f4b71Sopenharmony_ci uv_work_cb work_cb, 965e41f4b71Sopenharmony_ci uv_after_work_cb after_work_cb) 966e41f4b71Sopenharmony_ci``` 967e41f4b71Sopenharmony_ci 968e41f4b71Sopenharmony_ciwork_cb:提交给工作线程的任务。 969e41f4b71Sopenharmony_ci 970e41f4b71Sopenharmony_ciafter_work_cb:loop所在线程的要执行的回调函数。 971e41f4b71Sopenharmony_ci 972e41f4b71Sopenharmony_ci**注意:** work_cb与after_work_cb的执行有一个时序问题,只有work_cb执行完,通过`uv_async_send(loop->wq_async)`触发fd事件,loop所在线程在下一次迭代中才会执行after_work_cb。只有执行到after_work_cb时,与之相关的uv_work_t生命周期才算结束。 973e41f4b71Sopenharmony_ci 974e41f4b71Sopenharmony_ci下图为libuv的线程池工作流程,图中流程已简化,默认句柄的pending标志为1,worker线程个数不代表线程池中线程的真实数量。 975e41f4b71Sopenharmony_ci 976e41f4b71Sopenharmony_ci 977e41f4b71Sopenharmony_ci 978e41f4b71Sopenharmony_ci### OpenHarmony中libuv的使用现状 979e41f4b71Sopenharmony_ci 980e41f4b71Sopenharmony_ci当前OpenHarmony系统中涉及到libuv的线程主要有主线程、JS Worker线程、Taskpool中的TaskWorker线程以及IPC线程。除了主线程内采用了eventhandler作为主循环,其他线程都是使用libuv中的UV_RUN_DEFAULT运行模式作为当前线程的事件主循环来执行任务。在主线程中,eventhandler通过fd驱动的方式来触发任务的执行,eventhandler监听了uv_loop中的backend_fd。当loop中有fd事件触发的时候,eventhandler会执行一次`uv_run`来执行libuv中的任务。 981e41f4b71Sopenharmony_ci 982e41f4b71Sopenharmony_ci综上所述,开发者会发现这样一种现象:**同样的libuv接口在主线程上不生效,但在JS Worker线程中就没问题。这主要还是因为主线程上所有不通过触发fd来驱动的uv接口都不会得到及时的响应。** 983e41f4b71Sopenharmony_ci 984e41f4b71Sopenharmony_ci另外,在应用主线程中,所有的异步任务尽管最终都是通过libuv得到执行的。但是在当前系统中,[libuv的线程池已经对接到了FFRT中](https://gitee.com/openharmony/third_party_libuv/wikis/06-Wiki-%E6%8A%80%E6%9C%AF%E8%B5%84%E6%BA%90/%20libuv%E5%B7%A5%E4%BD%9C%E7%BA%BF%E7%A8%8B%E6%8E%A5%E5%85%A5FFRT%E6%96%B9%E6%A1%88%E5%88%86%E6%9E%90),任何抛向libuv的异步任务都会在FFRT的线程中得到调度。应用主线程的回调函数也通过PostTask接口插入到eventhandler的队列上。这就意味着ffrt线程上的异步任务完成后不再通过`uv_async_send`的方式触发主线程的回调。过程如下图: 985e41f4b71Sopenharmony_ci 986e41f4b71Sopenharmony_ci 987e41f4b71Sopenharmony_ci 988e41f4b71Sopenharmony_ci我们总结了五种类型的请求任务是直接可以按照正常用法在应用主循环中生效的: 989e41f4b71Sopenharmony_ci 990e41f4b71Sopenharmony_ci- uv_random_t 991e41f4b71Sopenharmony_ci 992e41f4b71Sopenharmony_ci 函数原型: 993e41f4b71Sopenharmony_ci 994e41f4b71Sopenharmony_ci```cpp 995e41f4b71Sopenharmony_ci/** 996e41f4b71Sopenharmony_ci* 将一个工作请求添加到事件循环的队列中。 997e41f4b71Sopenharmony_ci* 998e41f4b71Sopenharmony_ci* @param loop 事件循环 999e41f4b71Sopenharmony_ci* @param req 随机数请求 1000e41f4b71Sopenharmony_ci* @param buf 存储随机数的缓冲区 1001e41f4b71Sopenharmony_ci* @param buflen 缓冲区的长度 1002e41f4b71Sopenharmony_ci* @param flags 一个无符号整数,表示生成随机数的选项 1003e41f4b71Sopenharmony_ci* @param cb 随机数生成完成后的回调函数 1004e41f4b71Sopenharmony_ci* 1005e41f4b71Sopenharmony_ci* @return 成功返回0,失败返回错误码 1006e41f4b71Sopenharmony_ci*/ 1007e41f4b71Sopenharmony_ciint uv_random(uv_loop_t* loop, 1008e41f4b71Sopenharmony_ci uv_random_t* req, 1009e41f4b71Sopenharmony_ci void* buf, 1010e41f4b71Sopenharmony_ci size_t buflen, 1011e41f4b71Sopenharmony_ci unsigned flags, 1012e41f4b71Sopenharmony_ci uv_random_cb cb); 1013e41f4b71Sopenharmony_ci``` 1014e41f4b71Sopenharmony_ci 1015e41f4b71Sopenharmony_ci- uv_work_t 1016e41f4b71Sopenharmony_ci 1017e41f4b71Sopenharmony_ci 函数原型: 1018e41f4b71Sopenharmony_ci 1019e41f4b71Sopenharmony_ci```cpp 1020e41f4b71Sopenharmony_ci/** 1021e41f4b71Sopenharmony_ci* 将一个工作请求添加到事件循环的队列中。 1022e41f4b71Sopenharmony_ci* 1023e41f4b71Sopenharmony_ci* 当事件循环在下一次迭代时,work_cb函数将会在一个新的线程中被调用。 1024e41f4b71Sopenharmony_ci* 当work_cb函数完成时,after_work_cb函数将会在事件循环的线程中被调用。 1025e41f4b71Sopenharmony_ci* 1026e41f4b71Sopenharmony_ci* @param loop 事件循环 1027e41f4b71Sopenharmony_ci* @param req 工作请求 1028e41f4b71Sopenharmony_ci* @param work_cb 在新线程中被调用的函数 1029e41f4b71Sopenharmony_ci* @param after_work_cb 在事件循环线程中被调用的函数 1030e41f4b71Sopenharmony_ci* 1031e41f4b71Sopenharmony_ci* @return 成功返回0,失败返回-1 1032e41f4b71Sopenharmony_ci*/ 1033e41f4b71Sopenharmony_ciint uv_queue_work(uv_loop_t* loop, 1034e41f4b71Sopenharmony_ci uv_work_t* req, 1035e41f4b71Sopenharmony_ci uv_work_cb work_cb, 1036e41f4b71Sopenharmony_ci uv_after_work_cb after_work_cb); 1037e41f4b71Sopenharmony_ci``` 1038e41f4b71Sopenharmony_ci 1039e41f4b71Sopenharmony_ci- uv_fs_t 1040e41f4b71Sopenharmony_ci 1041e41f4b71Sopenharmony_ci 文件类提供的所有异步接口,在应用主线程中都是可以生效的。主要有如下: 1042e41f4b71Sopenharmony_ci 1043e41f4b71Sopenharmony_ci```cpp 1044e41f4b71Sopenharmony_ci/** 1045e41f4b71Sopenharmony_ci* 异步读取文件 1046e41f4b71Sopenharmony_ci* 1047e41f4b71Sopenharmony_ci* @param loop 事件循环 1048e41f4b71Sopenharmony_ci* @param req 文件操作请求 1049e41f4b71Sopenharmony_ci* @param file 文件描述符 1050e41f4b71Sopenharmony_ci* @param bufs 读取数据的缓冲区 1051e41f4b71Sopenharmony_ci* @param nbufs 缓冲区的数量 1052e41f4b71Sopenharmony_ci* @param off 文件的偏移量 1053e41f4b71Sopenharmony_ci* @param cb 完成后的回调函数 1054e41f4b71Sopenharmony_ci* @return 成功返回0,失败返回-1 1055e41f4b71Sopenharmony_ci*/ 1056e41f4b71Sopenharmony_ciint uv_fs_read(uv_loop_t* loop, uv_fs_t* req, 1057e41f4b71Sopenharmony_ci uv_file file, 1058e41f4b71Sopenharmony_ci const uv_buf_t bufs[], 1059e41f4b71Sopenharmony_ci unsigned int nbufs, 1060e41f4b71Sopenharmony_ci int64_t off, 1061e41f4b71Sopenharmony_ci uv_fs_cb cb); 1062e41f4b71Sopenharmony_ci 1063e41f4b71Sopenharmony_ci/** 1064e41f4b71Sopenharmony_ci* 异步打开文件 1065e41f4b71Sopenharmony_ci* 1066e41f4b71Sopenharmony_ci* @param loop 事件循环 1067e41f4b71Sopenharmony_ci* @param req 文件操作请求 1068e41f4b71Sopenharmony_ci* @param path 文件路径 1069e41f4b71Sopenharmony_ci* @param flags 打开文件的方式 1070e41f4b71Sopenharmony_ci* @param mode 文件权限 1071e41f4b71Sopenharmony_ci* @param cb 完成后的回调函数 1072e41f4b71Sopenharmony_ci* 1073e41f4b71Sopenharmony_ci* @return 成功返回0,失败返回-1 1074e41f4b71Sopenharmony_ci*/ 1075e41f4b71Sopenharmony_ciint uv_fs_open(uv_loop_t* loop, 1076e41f4b71Sopenharmony_ci uv_fs_t* req, 1077e41f4b71Sopenharmony_ci const char* path, 1078e41f4b71Sopenharmony_ci int flags, 1079e41f4b71Sopenharmony_ci int mode, 1080e41f4b71Sopenharmony_ci uv_fs_cb cb); 1081e41f4b71Sopenharmony_ci 1082e41f4b71Sopenharmony_ci/** 1083e41f4b71Sopenharmony_ci* 异步发送文件 1084e41f4b71Sopenharmony_ci* 1085e41f4b71Sopenharmony_ci* @param loop 事件循环 1086e41f4b71Sopenharmony_ci* @param req 文件操作请求 1087e41f4b71Sopenharmony_ci* @param out_fd 输出文件描述符 1088e41f4b71Sopenharmony_ci* @param in_fd 输入文件描述符 1089e41f4b71Sopenharmony_ci* @param off 文件的偏移量 1090e41f4b71Sopenharmony_ci* @param len 发送的长度 1091e41f4b71Sopenharmony_ci* @param cb 完成后的回调函数 1092e41f4b71Sopenharmony_ci* 1093e41f4b71Sopenharmony_ci* @return 成功返回0,失败返回-1 1094e41f4b71Sopenharmony_ci*/ 1095e41f4b71Sopenharmony_ciint uv_fs_sendfile(uv_loop_t* loop, 1096e41f4b71Sopenharmony_ci uv_fs_t* req, 1097e41f4b71Sopenharmony_ci uv_file out_fd, 1098e41f4b71Sopenharmony_ci uv_file in_fd, 1099e41f4b71Sopenharmony_ci int64_t off, 1100e41f4b71Sopenharmony_ci size_t len, 1101e41f4b71Sopenharmony_ci uv_fs_cb cb); 1102e41f4b71Sopenharmony_ci 1103e41f4b71Sopenharmony_ci/** 1104e41f4b71Sopenharmony_ci* 异步写入文件 1105e41f4b71Sopenharmony_ci* 1106e41f4b71Sopenharmony_ci* @param loop 事件循环 1107e41f4b71Sopenharmony_ci* @param req 文件操作请求 1108e41f4b71Sopenharmony_ci* @param file 文件描述符 1109e41f4b71Sopenharmony_ci* @param bufs 要写入的数据 1110e41f4b71Sopenharmony_ci* @param nbufs 数据的数量 1111e41f4b71Sopenharmony_ci* @param off 文件的偏移量 1112e41f4b71Sopenharmony_ci* @param cb 完成后的回调函数 1113e41f4b71Sopenharmony_ci* 1114e41f4b71Sopenharmony_ci* @return 成功返回0,失败返回-1 1115e41f4b71Sopenharmony_ci*/ 1116e41f4b71Sopenharmony_ciint uv_fs_write(uv_loop_t* loop, 1117e41f4b71Sopenharmony_ci uv_fs_t* req, 1118e41f4b71Sopenharmony_ci uv_file file, 1119e41f4b71Sopenharmony_ci const uv_buf_t bufs[], 1120e41f4b71Sopenharmony_ci unsigned int nbufs, 1121e41f4b71Sopenharmony_ci int64_t off, 1122e41f4b71Sopenharmony_ci uv_fs_cb cb); 1123e41f4b71Sopenharmony_ci 1124e41f4b71Sopenharmony_ci/** 1125e41f4b71Sopenharmony_ci* 异步复制文件 1126e41f4b71Sopenharmony_ci* 1127e41f4b71Sopenharmony_ci* @param loop 事件循环 1128e41f4b71Sopenharmony_ci* @param req 文件操作请求 1129e41f4b71Sopenharmony_ci* @param path 源文件路径 1130e41f4b71Sopenharmony_ci* @param new_path 目标文件路径 1131e41f4b71Sopenharmony_ci* @param flags 复制选项 1132e41f4b71Sopenharmony_ci* @param cb 完成后的回调函数 1133e41f4b71Sopenharmony_ci* 1134e41f4b71Sopenharmony_ci* @return 成功返回0,失败返回-1 1135e41f4b71Sopenharmony_ci*/ 1136e41f4b71Sopenharmony_ciint uv_fs_copyfile(uv_loop_t* loop, 1137e41f4b71Sopenharmony_ci uv_fs_t* req, 1138e41f4b71Sopenharmony_ci const char* path, 1139e41f4b71Sopenharmony_ci const char* new_path 1140e41f4b71Sopenharmony_ci int flags, 1141e41f4b71Sopenharmony_ci uv_fs_cb cb); 1142e41f4b71Sopenharmony_ci``` 1143e41f4b71Sopenharmony_ci 1144e41f4b71Sopenharmony_ci- uv_getaddrinfo_t 1145e41f4b71Sopenharmony_ci 1146e41f4b71Sopenharmony_ci 函数原型: 1147e41f4b71Sopenharmony_ci 1148e41f4b71Sopenharmony_ci```cpp 1149e41f4b71Sopenharmony_ci/** 1150e41f4b71Sopenharmony_ci* 异步获取地址信息 1151e41f4b71Sopenharmony_ci* 1152e41f4b71Sopenharmony_ci* @param loop 事件循环 1153e41f4b71Sopenharmony_ci* @param req 地址信息请求 1154e41f4b71Sopenharmony_ci* @param cb 完成后的回调函数 1155e41f4b71Sopenharmony_ci* @param hostname 主机名 1156e41f4b71Sopenharmony_ci* @param service 服务名 1157e41f4b71Sopenharmony_ci* @param hints 地址信息提示 1158e41f4b71Sopenharmony_ci* 1159e41f4b71Sopenharmony_ci* @return 成功返回0,失败返回-1 1160e41f4b71Sopenharmony_ci*/ 1161e41f4b71Sopenharmony_ciint uv_getaddrinfo(uv_loop_t* loop, 1162e41f4b71Sopenharmony_ci uv_getaddrinfo_t* req, 1163e41f4b71Sopenharmony_ci uv_getaddrinfo_cb cb, 1164e41f4b71Sopenharmony_ci const char* hostname, 1165e41f4b71Sopenharmony_ci const char* service, 1166e41f4b71Sopenharmony_ci const struct addrinfo* hints); 1167e41f4b71Sopenharmony_ci``` 1168e41f4b71Sopenharmony_ci 1169e41f4b71Sopenharmony_ci- uv_getnameinfo_t 1170e41f4b71Sopenharmony_ci 1171e41f4b71Sopenharmony_ci 函数原型: 1172e41f4b71Sopenharmony_ci 1173e41f4b71Sopenharmony_ci```cpp 1174e41f4b71Sopenharmony_ci/** 1175e41f4b71Sopenharmony_ci* 异步获取名称信息 1176e41f4b71Sopenharmony_ci* 1177e41f4b71Sopenharmony_ci* @param loop 事件循环 1178e41f4b71Sopenharmony_ci* @param req 名称信息请求 1179e41f4b71Sopenharmony_ci* @param getnameinfo_cb 完成后的回调函数 1180e41f4b71Sopenharmony_ci* @param addr 地址 1181e41f4b71Sopenharmony_ci* @param flags 标志 1182e41f4b71Sopenharmony_ci* 1183e41f4b71Sopenharmony_ci* @return 成功返回0,失败返回-1 1184e41f4b71Sopenharmony_ci*/ 1185e41f4b71Sopenharmony_ciint uv_getnameinfo(uv_loop_t* loop, 1186e41f4b71Sopenharmony_ci uv_getnameinfo_t* req, 1187e41f4b71Sopenharmony_ci uv_getnameinfo_cb getnameinfo_cb, 1188e41f4b71Sopenharmony_ci const struct sockaddr* addr, 1189e41f4b71Sopenharmony_ci int flags); 1190e41f4b71Sopenharmony_ci``` 1191e41f4b71Sopenharmony_ci 1192e41f4b71Sopenharmony_ci在应用主线程上不生效的接口主要包括: 1193e41f4b71Sopenharmony_ci 1194e41f4b71Sopenharmony_ci- idle句柄 1195e41f4b71Sopenharmony_ci- prepare句柄 1196e41f4b71Sopenharmony_ci- check句柄 1197e41f4b71Sopenharmony_ci- signal相关函数 1198e41f4b71Sopenharmony_ci- tcp及udp相关函数 1199e41f4b71Sopenharmony_ci 1200e41f4b71Sopenharmony_ci## 技术案例 1201e41f4b71Sopenharmony_ci 1202e41f4b71Sopenharmony_ci[libuv中主线程timer回调事件触发时间不正确原因](https://gitee.com/openharmony/third_party_libuv/wikis/06-Wiki-%E6%8A%80%E6%9C%AF%E8%B5%84%E6%BA%90/libuv%E4%B8%AD%E4%B8%BB%E7%BA%BF%E7%A8%8Btimer%E5%9B%9E%E8%B0%83%E4%BA%8B%E4%BB%B6%E8%A7%A6%E5%8F%91%E6%97%B6%E9%97%B4%E4%B8%8D%E6%AD%A3%E7%A1%AE%E5%8E%9F%E5%9B%A0) 1203e41f4b71Sopenharmony_ci 1204e41f4b71Sopenharmony_ci[libuv工作线程接入FFRT方案分析](https://gitee.com/openharmony/third_party_libuv/wikis/06-Wiki-%E6%8A%80%E6%9C%AF%E8%B5%84%E6%BA%90/%20libuv%E5%B7%A5%E4%BD%9C%E7%BA%BF%E7%A8%8B%E6%8E%A5%E5%85%A5FFRT%E6%96%B9%E6%A1%88%E5%88%86%E6%9E%90) 1205e41f4b71Sopenharmony_ci 1206e41f4b71Sopenharmony_ci[QoS感知的libuv、Node-API异步接口整改FAQ](https://gitee.com/openharmony/third_party_libuv/wikis/06-Wiki-%E6%8A%80%E6%9C%AF%E8%B5%84%E6%BA%90/QoS%E6%84%9F%E7%9F%A5%E7%9A%84libuv%E3%80%81napi%E5%BC%82%E6%AD%A5%E6%8E%A5%E5%8F%A3%E6%95%B4%E6%94%B9FAQ) 1207