在Timer模块中有提到,libuv控制着延迟事件的触发,那么必须想办法精确控制时间。
如果是JS,获取当前时间可以直接通过Date.now()得到一个时间戳,然后将两段时间戳相减得到时间差。一般情况下当然没有问题,但是这个方法并不保险,因为本地计算机时间可以修改。
libuv显然不会用这么愚蠢的办法来计算时间,C++内部有更为精妙的方法来处理这个事。
首先在上一节中,一个简单的事件轮询代码如下:
int main() { uv_loop_t *loop = uv_default_loop(); uv_run(loop, UV_RUN_DEFAULT); }
这里的uv_default_loop会生成一个默认的静态对象,负责管理事件轮询,而这个对象有一个属性,则负责记录当前的时间,如下:
/* The current time according to the event loop. in msecs. */ uint64_t time;
简单讲就是记录当前这一轮事件开始处理的时间,单位为毫秒。
在初始化之后,就会执行uv_run来开始事件轮询了,因为这节只讲时间,所以省略无关代码,如下:
int uv_run(uv_loop_t *loop, uv_run_mode mode) { // ... // 查询是否有未处理事件 r = uv__loop_alive(loop); if (!r) // 表示处理完一轮事件 更新时间 uv_update_time(loop); // 如果有未处理事件 while (r != 0 && loop->stop_flag == 0) { // 这里也会更新时间 uv_update_time(loop); // ... } }
可见,每次轮询时都会更新时间,方法就是那个uv_update_time,源码如下:
void uv_update_time(uv_loop_t* loop) { // 返回一个时间 uint64_t new_time = uv__hrtime(1000); // 检测数据合法性并赋值 assert(new_time >= loop->time); loop->time = new_time; } uint64_t uv__hrtime(double scale) { LARGE_INTEGER counter; if (hrtime_interval_ == 0) { return 0; } if (!QueryPerformanceCounter(&counter)) {

