libuv的事件驱动模型

libuv非常高效, 它利用事件驱动/异步IO, 实现线程的高度复用; 比如定时器, 网络传输等, 都可以使用同一个线程来执行. 本文是以unix/core.c为例.

int uv_run(uv_loop_t* loop, uv_run_mode mode) {
  int timeout;
  int r;
  int ran_pending;

  r = uv__loop_alive(loop);
  if (!r)
    uv__update_time(loop);

  //主循环
  while (r != 0 && loop->stop_flag == 0) {
    //获取当前系统时间, linux上调用系统的clock_gettime
	uv__update_time(loop);
	
	//检查定时器是否达到触发条件, 如果需要触发, 将执行timer的回调函数
    uv__run_timers(loop);
	
	//执行其它的待处理的任务, 比如网络事件, uv__io_poll触发网络事件时, 会将触发的socket存入poll_fds
    ran_pending = uv__run_pending(loop);
	
	//uv__run_idle和uv__run_prepare是用宏定义出来的, IDE没办法直接找到它的定义; 
	//见loop-watcher.c中的#define UV_LOOP_WATCHER_DEFINE(name, type)
	
	//监听idle事件和prepare事件, 它们的本质是一样的; 如果设置了这样的事件, 则本循环将一直循环, 不会停顿;
    uv__run_idle(loop);
    uv__run_prepare(loop);

	//计算下一次需要定时的时间; 如果设置了idle或者是prepare事件, 这个值为0, 否则就是timer中最短的那个超时时间
    timeout = 0;
    if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
      timeout = uv_backend_timeout(loop);

	//linux调用epoll来监听网络事件, 并利用它实现定时
    uv__io_poll(loop, timeout);
	
	//与uv__run_idle, uv__run_prepare一样的机制, 用的少
    uv__run_check(loop);
	
	//close的相关操作也可以是异步的.
    uv__run_closing_handles(loop);

    if (mode == UV_RUN_ONCE) {
      /* UV_RUN_ONCE implies forward progress: at least one callback must have
       * been invoked when it returns. uv__io_poll() can return without doing
       * I/O (meaning: no callbacks) when its timeout expires - which means we
       * have pending timers that satisfy the forward progress constraint.
       *
       * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
       * the check.
       */
      uv__update_time(loop);
      uv__run_timers(loop);
    }

    r = uv__loop_alive(loop);
    if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
      break;
  }

  /* The if statement lets gcc compile it to a conditional store. Avoids
   * dirtying a cache line.
   */
  if (loop->stop_flag != 0)
    loop->stop_flag = 0;

  return r;
}

在由loop调用的各种回调函数中, 添加或删除定时器, 或创建/销毁新的网络连接, 是安全的. 但是如果在其它的线程中, 直接调用loop的接口, 不是线程安全的, 非常危险. 所以libuv通常的例子是这样的:

int main() {
    loop = uv_default_loop();
    //在loop循环之前, 先把各种定时或网络任务设置好.
    uv_timer_init(loop, &gc_req);
    uv_unref((uv_handle_t*) &gc_req);

    uv_timer_start(&gc_req, gc, 0, 2000);

    // could actually be a TCP download or something
    uv_timer_init(loop, &fake_job_req);
    uv_timer_start(&fake_job_req, fake_job, 9000, 0);
	
	//各种定时任务初始化完成之后, 再执行loop循环
    return uv_run(loop, UV_RUN_DEFAULT);
}

转载于:https://my.oschina.net/u/2343729/blog/1828061

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值