libuv学习笔记(7)

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);
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值