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_ciindex.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![线程间通信原理](./figures/libuv-image-1.png)
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![libuv线程池工作原理](./figures/libuv-image-3.png)
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![libuv的异步线程池在OpenHarmony中的应用现状](./figures/libuv-ffrt.png)
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