libuv学习笔记(7)
uv_async_t 数据结构与相关API
用来从另一个线程与loop所在线程交互,主要是唤醒loop(通过PostQueuedCompletionStatus向iocp端口发送事件)
数据结构
typedef struct uv_async_s uv_async_t;
struct uv_async_s
{
UV_HANDLE_FIELDS//uv_handle_t的成员,此处不再展开,请参考之前的内容
//UV_ASYNC_PRIVATE_FIELDS展开如下:
//请求,内部使用
struct uv_req_s async_req;
//回调函数
uv_async_cb async_cb;
//避免多次发送相同的请求(通过PostQueuedCompletionStatus)
char volatile async_sent;
};
通过char volatile async_sent;成员可以实现多次调用uv_async_send发送同一uv_async_t,在请求被处理之前,内部其实只会发送一次(通过PostQueuedCompletionStatus),也就是回调函数只会被调用一次。
相关API函数
初始化,导出函数,在uv.h中声明,async.c中定义
在初始化时会与loop联系起来,并在内部初始化一个wakeup类型的请求
可以看出本函数并非是线程安全的,所以需要在uv_run之前调用或者与uv_run在同一线程调用(个人观点)。
int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb)
{
uv_req_t* req;
//初始化handle,将handle与传入的loop联系起来,并添加到loop的handle队列中
uv__handle_init(loop, (uv_handle_t*) handle, UV_ASYNC);
handle->async_sent = 0;//初始化为0
handle->async_cb = async_cb;
req = &handle->async_req;
uv_req_init(loop, req);//初始化请求
req->type = UV_WAKEUP;//类型为wakeup
req->data = handle;
//激活handle,状态变为UV__HANDLE_ACTIVE,loop活动handle计数加一
uv__handle_start(handle);
return 0;
}
发送请求
唤醒loop以便调用回调函数,线程安全的,可以在其他线程调用
int uv_async_send(uv_async_t* handle)
{
uv_loop_t* loop = handle->loop;
if (handle->type != UV_ASYNC) {
/* Can't set errno because that's not thread-safe. */
return -1;
}
//用户必须保证发送的uv_async_t不是关闭或正在关闭状态
assert(!(handle->flags & UV__HANDLE_CLOSING));
//原子方式改变async_sent,这样就实现了多次调用send发送同一个uv_async_t,在回调调用一次之前,不回
//多次调用
if (!uv__atomic_exchange_set(&handle->async_sent)) //函数返回async_sent原来的值,并将其
//设置为1
{
//POST_COMPLETION_FOR_REQ(loop, &handle->async_req);展开:
//向iocp端口发送事件
if (!PostQueuedCompletionStatus((loop)->iocp,
0,
0,
&((req)->u.io.overlapped)))
{
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
}
return 0;
}
uv_run对于wakeup类型请求的处理(通过uv_process_reqs函数)
uv_run在i/o轮询是会获取到send发送的事件,并将uv_async_t内部的请求添加到loop的pending_reqs_tail列表。
//遍历每一个请求做处理
...
switch (req->type) {
...
case UV_WAKEUP:
uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req);
break;
...
void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
uv_req_t* req)
{
assert(handle->type == UV_ASYNC);
assert(req->type == UV_WAKEUP);
//还原标记为0
handle->async_sent = 0;
//如果handle正在关闭(调用了uv_close),将handle加入关闭handle队列,不再调用回调函数
if (handle->flags & UV__HANDLE_CLOSING) {
uv_want_endgame(loop, (uv_handle_t*)handle);
} else if (handle->async_cb != NULL) {
handle->async_cb(handle);//调用回调
}
}
uv_close关闭uv_async_t时的处理
case UV_ASYNC:
uv_async_close(loop, (uv_async_t*) handle);
return;
void uv_async_close(uv_loop_t* loop, uv_async_t* handle)
{
//没有发送或者异步请求已经处理完成
if (!((uv_async_t*)handle)->async_sent)
{
uv_want_endgame(loop, (uv_handle_t*) handle);
}
//状态改为UV__HANDLE_CLOSING
//对于uv_async_t而言,在请求发出当尚未被处理的情况下,closing状态下仍然是active的,一直要等到
//loop在处理其请求时才能将其添加到关闭队列。
uv__handle_closing(handle);
}
uv_want_endgame会将需要关闭的句柄添加到loop的关闭句柄列表,最终在uv_run中通过uv_process_endgames处理所有需要关闭的handle
case UV_ASYNC:
uv_async_endgame(loop, (uv_async_t*) handle);
break;
void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle)
{
if (handle->flags & UV__HANDLE_CLOSING &&
!handle->async_sent)
{
assert(!(handle->flags & UV_HANDLE_CLOSED));
//从loop的handle列表中去掉,递减活动handle的计数,调用关闭回调函数
uv__handle_close(handle);
}
}