I、Linux中与时间相关的函数
a、 获取当前时间,计算时间间隔;
time(2) / time_t (秒) ----->精度太低
ftime(3) / struct timeb (毫秒) ---->已被废弃
gettimeofday(2) / struct timeval (微秒) ----->满足日常计时的需要,推荐使用。
clock_gettime(2) / struct timespec (纳秒) ----->精度最高,但是它系统调用的开销大。
b、时区转换与日期计算;如把纽约当地时间转换为上海当地时间;
gmtime / localtime / timegm / mktime / strftime / struct tm
c、定时操作,比如在预定的时间执行一项任务,或者在一段延时之后执行一项任务。
sleep、alarm、usleep --->实现时有可能用了信号 SIGALRM,在多线程程序中处理信号是个相当麻烦的事情,应当尽量避免.
nanosleep、clock_nanosleep --->线程安全的,但是在非阻塞网络编程中,绝对不能用让线程挂起的方式来等待一段时间,程序会失去响应。
*itimer、timer_* --->用信号来 deliver 超时,在多线程程序中也会有麻烦。
timerfd_* --->把时间变成了一个文件描述符,能很方便地融入到 select/poll 框架中,用统一的方式来处理 IO 事件和超时事件
II、timerfd_*系列函数讲解:
1、用到的系统时钟:
-->CLOCK_REALTIME:代表机器上可以理解为当前的我们所常看的时间,其当time-of-day 被修改的时候而改变
-->CLOCK_MONOTONIC:代表从过去某个固定的时间点开始的绝对的逝去时间,它不受任何系统time-of-day时钟修改的影响
2、涉及的函数:
timerfd_create:
@function:生成一个定时器对象;
@param1: clockid, 填写CLOCK_REALTIME或者CLOCK_MONOTONIC,表示使用哪个时钟来标示定时器的进展;
@param2: flags, TFD_NONBLOCK(非阻塞,read(fd)如果没有超时发生就直接返回; 默认read(fd)阻塞到超时发生时返回)
@return: 相应的文件描述符
timerfd_settime:
@function:启动和停止定时器;
@param1: fd, 上个函数返回的文件描述符;
@param2: flags, 0(相对定时器)或者TFD_TIMER_ABSTIME(绝对定时器)
@param3: new_value, 指定第一次超时时间和间隔超时时间
@param4: old_value, 返回此函数调用时定时器的时间设置情况(可以使用timerfd_gettime获取)
@return: 成功返回0,失败返回-1;
III、示例代码
#include <sys/timerfd.h>
#include <string.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;
struct timespec curr;
uint64_t exp, tot_exp;
ssize_t s;
/* 分别使用不同的时钟创建timerfd */
fd = timerfd_create(CLOCK_MONOTONIC, 0);
//fd = timerfd_create(CLOCK_REALTIME, 0);
if (fd == -1)
handle_error("timerfd_create");
#if 0
/* MONOTONIC的绝对定时器 */
if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1)
handle_error("clock_gettime");
new_value.it_value.tv_sec = curr.tv_sec + 3;
new_value.it_value.tv_nsec = curr.tv_nsec;
#endif
#if 0
/* REALTIME的绝对定时器 */
if (clock_gettime(CLOCK_REALTIME, &now) == -1)
handle_error("clock_gettime");
new_value.it_value.tv_sec = now.tv_sec + 3;
new_value.it_value.tv_nsec = now.tv_nsec;
#endif
/* 相对定时器 */
bzero(&new_value, sizeof(new_value));
new_value.it_value.tv_sec = 3;
//if (timerfd_settime(fd, TFD_TIMER_ABSTIME, &new_value, NULL) == -1)
if (timerfd_settime(fd, 0, &new_value, NULL) == -1)
handle_error("timerfd_settime");
print_elapsed_time();
printf("timer started\n");
s = read(fd, &exp, sizeof(uint64_t));
if (s != sizeof(uint64_t))
handle_error("read");
tot_exp += exp;
print_elapsed_time();
printf("read: %llu", (unsigned long long) exp);
exit(EXIT_SUCCESS);
}