精度比较高的系统调用有这三个。

futex

1
2
3
int futex(int * uaddr ,int futex_op ,int val ,
const struct timespec * timeout , / *或:uint32_t val2 * /
int * uaddr2 ,int val3 );

其中timeout参数的精度是纳秒,futex会在timeout到期时,不再阻塞。

若timeout为0,则futex会无限期阻塞。

在golang1.13之前,定时器相关的函数,例如sleep,time.Tick等,用的是futex系统调用来控制超时。

另外,golang里的mutex锁也是以来futex来实现,不再赘述。

nanosleep

1
int nanosleep(const struct timespec *req, struct timespec *rem);

同futex一样,timespec的精度为纳秒,linux系统命令sleep使用的是该系统调用。

epoll_wait

1
2
3
4
5
int epoll_wait(int epfd ,struct epoll_event * events ,
int maxevents ,int timeout );
int epoll_pwait(int epfd ,struct epoll_event * events ,
int maxevents ,int timeout ,
const sigset_t * sigmask );

timeout精度为毫秒,go1.14之后sleep,time.After等定时器相关的函数,底层将由futex换为epoll_wait来控制。

这篇文章 Linux下定时器的设计与实现不错,放在这里做个补充