timerfd及timerfd_create,timerfd_settime,timerfd_gettime函数
1. timerfd 介绍
timerfd是Linux为用户程序提供的一个定时器接口。
这个接口基于文件描述符,通过文件描述符的可读事件进行超时通知,所以能够被用于select/poll的应用场景。
1.1 man timerfd_create
These system calls create and operate on a timer that delivers timer expiration notifications via a file descriptor.
这三个系统调用创建并操作计时器,该计时器通过文件描述符传递计时器过期通知。
2. timerfd_ 三个函数接口
#include <sys/timerfd.h>
int timerfd_create(int clockid, int flags);
创建一个定时器描述符timerfd
int timerfd_settime(int fd, int flags,
const struct itimerspec *new_value,
struct itimerspec *old_value);
用来启动或关闭有fd指定的定时器
int timerfd_gettime(int fd, struct itimerspec *curr_value);
此函数用于获得定时器距离下次超时还剩下的时间。
2.1 timerfd_create 参数说明:
- clockid指定时间类型,有两个值:
CLOCK_REALTIME :Systemwide realtime clock. 系统范围内的实时时钟
CLOCK_MONOTONIC:以固定的速率运行,从不进行调整和复位 ,它不受任何系统time-of-day时钟修改的影响 - flags可以是0或者O_CLOEXEC/O_NONBLOCK。
一般是0 - 返回值:timerfd(文件描述符)
2.2 timerfd_settime 参数说明:
-
fd timerfd_create的返回值
-
flags:1代表设置的是绝对时间;为0代表相对时间。
The flags argument is either 0, to start a relative timer , or TFD_TIMER_ABSTIME, to start an absolute timer -
new_value 指定新的超时时间
设定new_value.it_value非零则启动定时器,否则关闭定时器,如果new_value.it_interval为0,则定时器只定时一次,即初始那次,否则之后每隔设定时间超时一次 -
old_value:不为null,则返回定时器这次设置之前的超时时间
一般为0 -
结构 itimerspec 定义
struct timespec {
time_t tv_sec; /* Seconds /
long tv_nsec; / Nanoseconds */
};struct itimerspec {
struct timespec it_interval; /* Interval for periodic timer /
struct timespec it_value; / Initial expiration */
};
2.3 timerfd_gettime 参数说明:
- fd timerfd_create的返回值
3. man 自带timerfd代码示例
#include <sys/timerfd.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h> /* Definition of uint64_t */
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
static void
print_elapsed_time(void)
{
static struct timespec start;
struct timespec curr;
static int first_call = 1;
int secs, nsecs;
if (first_call) {
first_call = 0;
if (clock_gettime(CLOCK_MONOTONIC, &start) == -1)
handle_error("clock_gettime");
}
if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1)
handle_error("clock_gettime");
secs = curr.tv_sec - start.tv_sec;
nsecs = curr.tv_nsec - start.tv_nsec;
if (nsecs < 0) {
secs--;
nsecs += 1000000000;
}
printf("%d.%03d: ", secs, (nsecs + 500000) / 1000000);
}
int
main(int argc, char *argv[])
{
struct itimerspec new_value;
int max_exp, fd;
struct timespec now;
uint64_t exp, tot_exp;
ssize_t s;
if ((argc != 2) && (argc != 4)) {
fprintf(stderr, "%s init-secs [interval-secs max-exp]\n",
argv[0]);
exit(EXIT_FAILURE);
}
if (clock_gettime(CLOCK_REALTIME, &now) == -1)
handle_error("clock_gettime");
/* Create a CLOCK_REALTIME absolute timer with initial
expiration and interval as specified in command line */
new_value.it_value.tv_sec = now.tv_sec + atoi(argv[1]);
new_value.it_value.tv_nsec = now.tv_nsec;
if (argc == 2) {
new_value.it_interval.tv_sec = 0;
max_exp = 1;
} else {
new_value.it_interval.tv_sec = atoi(argv[2]);
max_exp = atoi(argv[3]);
}
new_value.it_interval.tv_nsec = 0;
fd = timerfd_create(CLOCK_REALTIME, 0);
if (fd == -1)
handle_error("timerfd_create");
if (timerfd_settime(fd, TFD_TIMER_ABSTIME, &new_value, NULL) == -1)
handle_error("timerfd_settime");
print_elapsed_time();
printf("timer started\n");
for (tot_exp = 0; tot_exp < max_exp;) {
s = read(fd, &exp, sizeof(uint64_t));
if (s != sizeof(uint64_t))
handle_error("read");
tot_exp += exp;
print_elapsed_time();
printf("read: %llu; total=%llu\n",
(unsigned long long) exp,
(unsigned long long) tot_exp);
}
exit(EXIT_SUCCESS);
}
说明:
-
main接收1个或3个参数
参数含义分别是:初始超时时间,间隔超时时间,超时次数 -
read读取timefd超时事件通知
当定时器超时,read读事件发生即可读,返回超时次数(从上次调用timerfd_settime()启动开始或上次read成功读取开始),它是一个8字节的unit64_t类型整数,如果定时器没有发生超时事件,则read将阻塞若timerfd为阻塞模式,否则返回EAGAIN 错误(O_NONBLOCK模式),如果read时提供的缓冲区小于8字节将以EINVAL错误返回。
结果:
[root@glusterfs home]# ./a.out 2 1 5
0.000: timer started
1.1000: read: 1; total=1
2.1000: read: 1; total=2
3.1000: read: 1; total=3
5.000: read: 1; total=4
6.000: read: 1; total=5
[root@glusterfs home]#
[root@glusterfs home]# ./a.out 2
0.000: timer started
1.1000: read: 1; total=1
[root@glusterfs home]#
参考:
https://www.cnblogs.com/mickole/p/3261879.html
https://man7.org/linux/man-pages/man2/timerfd_create.2.html