Libuv可用的工具集合
This chapter catalogues tools and techniques which are useful for common tasks. The libev man page already covers some patterns which can be adopted to libuv through simple API changes. It also covers parts of the libuv API that don’t require entire chapters dedicated to them.
定时器(Timers)
Timers invoke the callback after a certain time has elapsed since the timer was started. libuv timers can also be set to invoke at regular intervals instead of just once.
Simple use is to init a watcher and start it with a timeout
, and optional repeat
. Timers can be stopped at any time.
uv_timer_t timer_req; uv_timer_init(loop, &timer_req); uv_timer_start(&timer_req, callback, 5000, 2000);
will start a repeating timer, which first starts 5 seconds (the timeout
) after the execution of uv_timer_start
, then repeats every 2 seconds (the repeat
). Use:
uv_timer_stop(&timer_req);
to stop the timer. This can be used safely from within the callback as well.
The repeat interval can be modified at any time with:
uv_timer_set_repeat(uv_timer_t *timer, int64_t repeat);
which will take effect when possible. If this function is called from a timer callback, it means:
- If the timer was non-repeating, the timer has already been stopped. Use
uv_timer_start
again. - If the timer is repeating, the next timeout has already been scheduled, so the old repeat interval will be used once more before the timer switches to the new interval.
The utility function:
int uv_timer_again(uv_timer_t *)
applies only to repeating timers and is equivalent to stopping the timer and then starting it with both initial timeout
and repeat
set to the old repeat
value. If the timer hasn’t been started it fails (error code UV_EINVAL
) and returns -1.
An actual timer example is in the reference count section.
事件循环引用计数(Event loop reference count)
The event loop only runs as long as there are active watchers. This system works by having every watcher increase the reference count of the event loop when it is started and decreasing the reference count when stopped. It is also possible to manually change the reference count of handles using:
void uv_ref(uv_handle_t*); void uv_unref(uv_handle_t*);
These functions can be used to allow a loop to exit even when a watcher is active or to use custom objects to keep the loop alive.
The former can be used with interval timers. You might have a garbage collector which runs every X seconds, or your network service might send a heartbeat to others periodically, but you don’t want to have to stop them along all clean exit paths or error scenarios. Or you want the program to exit when all your other watchers are done. In that case just unref the timer immediately after creation so that if it is the only watcher running then uv_run
will still exit.
The later is used in node.js where some libuv methods are being bubbled up to the JS API. A uv_handle_t
(the superclass of all watchers) is created per JS object and can be ref/unrefed.
ref-timer/main.c
uv_loop_t *loop; uv_timer_t gc_req; uv_timer_t fake_job_req; int main() { loop = uv_default_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); return uv_run(loop, UV_RUN_DEFAULT); }
We initialize the garbage collector timer, then immediately unref
it. Observe how after 9 seconds, when the fake job is done, the program automatically exits, even though the garbage collector is still running.
空闲监视器模式(Idle watcher pattern)
The callbacks of idle watchers are only invoked when the event loop has no other pending events. In such a situation they are invoked once every iteration of the loop. The idle callback can be used to perform some very low priority activity. For example, you could dispatch a summary of the daily application performance to the developers for analysis during periods of idleness, or use the application’s CPU time to perform SETI calculations