Setting the Current Time of Day
#define _SVID_SOURCE
#include
int stime(time_t *t);
成功返回0,失败返回-1并设置errno。
//example
time_t t = 1;
int ret;
/* set time to one second after the epoch */
ret = stime(&t);
if(ret)
perror("stime");
Setting Time with Precision
#include
int settimeofday(const struct timeval *tv,
const struct timezone *tz);
passing NULL for tz is the best practice
成功返回0, 失败返回-1。
// set the current time to a Saturday
//in the middle of December 1979
struct timeval tv = {.tv_sec = 31415926,
.tv_usec = 27182818};
int ret;
ret = settimeofday(&tv, NULL);
if(ret)
perror("settimeofday");
An Advanced Interface for Setting the Time
#include
int clock_settime(clockid_t clock_id,
const struct timespec *ts);
成功返回0,失败返回-1,并设置errno。
Playing with Time
#include
char *asctime(const struct tm *tm);
char *asctime_r(const struct tm *tm, char *buf);
成功返回字符串, 失败返回NULL。
//转换tm结构,但它将其转换为time_t。
#include
time_t mktime(struct tm *tm);
失败返回-1。
//将time_t转换为其ASCII表示形式
#include
char * ctime (const time_t *timep);
char * ctime_r (const time_t *timep, char *buf);
失败返回NULL。
t = time (NULL);
printf ("the time a mere line ago: %s", ctime (&t));
线程程序应该使用ctime_r()
缓冲区的长度必须至少为26个字符。
gmtime()将给定的time_t转换为tm结构,表示为UTC时区:
#include
struct tm * gmtime (const time_t *timep);
struct tm * gmtime_r (const time_t *timep, struct tm *result);
失败返回NULL。
#include
struct tm * localtime (const time_t *timep);
struct tm * localtime_r (const time_t *timep, struct tm *result);
difftime()返回两个time_t值之间的秒数,强制转换为double:
#include
double difftime (time_t time1, time_t time0);
Tuning the System Clock
#define _BSD_SOURCE
#include
int adjtime (const struct timeval *delta,
struct timeval *olddelta);
#include
int adjtimex (struct timex *adj);
调用adjtimex()将内核时间相关参数读取到adj指向的timex结构中。\
struct timex {
int modes; /* mode selector */
long offset; /* time offset (usec) */
long freq; /* frequency offset (scaled ppm) */
long maxerror; /* maximum error (usec) */
long esterror; /* estimated error (usec) */
int status; /* clock status */
long constant; /* PLL time constant */
long precision; /* clock precision (usec) */
long tolerance; /* clock frequency tolerance (ppm) */
struct timeval time; /* current time */
long tick; /* usecs between clock ticks */
};
Sleeping and Waiting
#include
unsigned int sleep (unsigned int seconds);
Sleeping with Microsecond Precision
/* BSD version */
#include
void usleep (unsigned long usec);
/* SUSv2 version */
#define _XOPEN_SOURCE 500
#include
int usleep (useconds_t usec);
errno = 0;
usleep (1000);
if (errno)
perror ("usleep");
Sleeping with Nanosecond Resolution
#define _POSIX_C_SOURCE 199309
#include
int nanosleep (const struct timespec *req,
struct timespec *rem);
struct timespec req = { .tv_sec = 0, .tv_nsec = 200 };
/* sleep for 200 ns */
ret = nanosleep (&req, NULL);
if (ret)
perror ("nanosleep");
struct timespec req = { .tv_sec = 0, .tv_nsec = 1369 };
struct timespec rem;
int ret;
/* sleep for 1369 ns */
retry:
ret = nanosleep (&req, &rem);
if (ret) {
if (errno == EINTR) {
/* retry, with the provided time remaining */
req.tv_sec = rem.tv_sec;
req.tv_nsec = rem.tv_nsec;
goto retry;
}
perror ("nanosleep");
}
struct timespec req = { .tv_sec = 1, .tv_nsec = 0 };
struct timespec rem, *a = &req, *b = &rem;
/* sleep for 1s */
while (nanosleep (a, b) && errno == EINTR) {
struct timespec *tmp = a;
a = b;
b = tmp;
}
An Advanced Approach to Sleep
#include
int clock_nanosleep (clockid_t clock_id,
int flags,
const struct timespec *req,
struct timespec *rem);
ret = nanosleep (&req, &rem);
==
ret = clock_nanosleep (CLOCK_REALTIME, 0, &req, &rem);
struct timespec ts = { .tv_sec = 1, .tv_nsec = 500000000 };
int ret;
ret = clock_nanosleep (CLOCK_MONOTONIC, 0, &ts, NULL);
if (ret)
perror ("clock_nanosleep");
int ret;
/* we want to sleep until one second from NOW */
ret = clock_gettime (CLOCK_MONOTONIC, &ts);
if (ret) {
perror ("clock_gettime");
return;
}
ts.tv_sec += 1;
printf ("We want to sleep until sec=%ld nsec=%ld\n",
ts.tv_sec, ts.tv_nsec);
ret = clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL);
if (ret)
perror ("clock_nanosleep");
A Portable Way to Sleep
#include
int select (int n,
fd_set *readfds,
fd_set *writefds,
fd_set *exceptfds,
struct timeval *timeout);
struct timeval tv = { .tv_sec = 0, .tv_usec = 757 };
/* sleep for 757 us */
select (0, NULL, NULL, NULL, &tv);
Overruns
就是说比如系统的timer ticks 是10ms, 但请求了一个1ms的sleep, 系统是达不到这个精度的, 所以会比期待的1ms的延时长,会是10ms, 会比原来长9ms。
Alternatives to Sleeping
Timers
Simple Alarms
#include
unsigned int alarm(unsigned int seconds);
void alarm_handler (int signum) {
printf ("Five seconds passed!\n");
}
void func (void) {
signal (SIGALRM, alarm_handler);
alarm (5);
pause ();
}
## Interval Timers
#include
int getitimer (int which, struct itimerval *value);
int setitimer (int which, const struct itimerval *value,
struct itimerval *ovalue);
间隔计时器的工作方式类似于告警(),但也可以自动重新武装自己,并在以下三种不同模式中的一种模式下操作:
- ITIMER_REAL
实时测量。当指定的实时时间已经过去时,内核将向进程发送一个SIGALRM信号。 - ITIMER_VIRTUAL
只有在进程的用户空间代码正在执行时才会减少。当指定的进程时间已过时,内核将向进程发送SIGVTALRM。 - ITIMER_PROF
进程执行时和内核代表进程执行时(例如,完成系统调用)都会减少。当指定的时间已经过去时, 内核向进程发送SIGPROF信号。此模式通常与ITIMER_VUALUAL耦合,以便程序能够测量进程所花费的用户和内核时间。
struct itimerval {
struct timeval it_interval; /* next value */
struct timeval it_value; /* current value */
};
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
void alarm_handler (int signo) {
printf ("Timer hit!\n");
}
void foo (void) {
struct itimerval delay;
int ret;
signal (SIGALRM, alarm_handler);
delay.it_value.tv_sec = 5;
delay.it_value.tv_usec = 0;
delay.it_interval.tv_sec = 1;
delay.it_interval.tv_usec = 0;
ret = setitimer (ITIMER_REAL, &delay, NULL);
if (ret) {
perror ("setitimer");
return; }
pause ();
}
Advanced Timer
Creating a timer
#include
#include
int timer_create (clockid_t clockid, struct sigevent *evp, timer_t *timerid);
timer_t timer;
int ret;
ret = timer_create (CLOCK_PROCESS_CPUTIME_ID, NULL, &timer);
if (ret)
perror ("timer_create");
#include
struct sigevent {
union sigval sigev_value;
int sigev_signo;
int sigev_notify;
void (*sigev_notify_function)(union sigval);
pthread_attr_t *sigev_notify_attributes;
};
union sigval {
int sival_int;
void *sival_ptr;
};
The following example creates a timer keyed off CLOCK_REALTIME. When the timer ex‐pires, the kernel will issue the SIGUSR1 signal and set si_value to the address storing the timer’s ID:
struct sigevent evp;
timer_t timer;
int ret;
evp.sigev_value.sival_ptr = &timer;
evp.sigev_notify = SIGEV_SIGNAL;
evp.sigev_signo = SIGUSR1;
ret = timer_create (CLOCK_REALTIME, &evp, &timer);
if (ret)
perror ("timer_create");
Arming a timer
include
int timer_settime (timer_t timerid, int flags, const struct itimerspec *value,
struct itimerspec *ovalue);
struct itimerspec {
struct timespec it_interval; /* next value /
struct timespec it_value; / current value */
};
Using the timer value initialized earlier by timer_create(), the following example
creates a periodic timer that expires every second:
struct itimerspec ts;
int ret;
ts.it_interval.tv_sec = 1;
ts.it_interval.tv_nsec = 0;
ts.it_value.tv_sec = 1;
ts.it_value.tv_nsec = 0;
ret = timer_settime (timer, 0, &ts, NULL);
if (ret)
perror ("timer_settime");
### Obtaining the expiration of a timer
include
int timer_gettime (timer_t timerid, struct itimerspec *value);
struct itimerspec ts;
int ret;
ret = timer_gettime (timer, &ts);
if (ret)
perror ("timer_gettime");
else {
printf ("current sec=%ld nsec=%ld\n",
ts.it_value.tv_sec, ts.it_value.tv_nsec);
printf ("next sec=%ld nsec=%ld\n",
ts.it_interval.tv_sec, ts.it_interval.tv_nsec);
}
### Obtaining the overrun of a timer
include
int timer_getoverrun (timer_t timerid);
//example
int ret;
ret = timer_getoverrun (timer);
if (ret == −1)
perror ("timer_getoverrun");
else if (ret == 0)
printf ("no overrun\n");
else
printf ("%d overrun(s)\n", ret);
### Deleting a timer
include
int timer_delete (timer_t timerid);