#2949·libuv

unix: uv_async_send takes long latency on single core CPU again

Author: Parallel-HaoCreated Aug 5, 2020Updated Aug 28, 2026
Labelsnot-stale
  • Version: v1.x
  • Platform: Linux 4.15.0-88-generic

The relevant issue: https://github.com/libuv/libuv/issues/2769 The commit to solve the issue: https://github.com/libuv/libuv/commit/a9d9d4ea1b628368170fea18b042483f850e48a1

The test case is almost same as the above issue, including two threads, one (A) for libuv event loop and the other one (B) for sending event requests. Also, the process is pinned to one core. The difference with the above issue is that this time thread B does some computation (e.g., matrix multiplication) before sending event requests. The experiment shows the more computation thread B does, the longer latency the uv_async_send() takes. Further, I found the sched_yield() introduced from the above commit cannot truly yield CPU, which means thread A spins until running out its time slice in the case that thread B has heavy computations.

My guess is Linux CFS scheduler try not to schedule thread B for fairness in such case, since the computation of thread B consumed too much time slice compared to A. However, the fairness breaks the semantics here that thread A should yield CPU with 100% chance. According to sched_yield() manual, this function just moves the calling thread to the end of the scheduling queue and does not guarantee to schedule other threads. It seems no system call in Linux is provided to truly yield CPU.

After some search and try, it seems that sleep(0) is able to provide such truly (very high chance at least) yield function. Although this solution fixes my problem successfully, I am not sure this is the final solution for libuv. Because sleep() implemented by glibc is based on nanosleep() system call, which works for Linux, it is a concern whether sleep(0) can apply to other *nix systems.