Setting the Current Time of Day
#define _SVID_SOURCE
#include <time.h>
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 <sys/time.h>
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 <time.h>
int clock_settime(clockid_t clock_id,
const struct timespec *ts);
成功返回0,失敗返回-1,并設置errno褐奴。
Playing with Time
#include <time.h>
char *asctime(const struct tm *tm);
char *asctime_r(const struct tm *tm, char *buf);
成功返回字符串, 失敗返回NULL于毙。
//轉(zhuǎn)換tm結(jié)構(gòu)敦冬,但它將其轉(zhuǎn)換為time_t。
#include <time.h>
time_t mktime(struct tm *tm);
失敗返回-1唯沮。
//將time_t轉(zhuǎn)換為其ASCII表示形式
#include <time.h>
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()
緩沖區(qū)的長度必須至少為26個字符。
gmtime()將給定的time_t轉(zhuǎn)換為tm結(jié)構(gòu)介蛉,表示為UTC時區(qū):
#include <time.h>
struct tm * gmtime (const time_t *timep);
struct tm * gmtime_r (const time_t *timep, struct tm *result);
失敗返回NULL萌庆。
#include <time.h>
struct tm * localtime (const time_t *timep);
struct tm * localtime_r (const time_t *timep, struct tm *result);
difftime()返回兩個time_t值之間的秒數(shù),強制轉(zhuǎn)換為double:
#include <time.h>
double difftime (time_t time1, time_t time0);
Tuning the System Clock
#define _BSD_SOURCE
#include <sys/time.h>
int adjtime (const struct timeval *delta,
struct timeval *olddelta);
#include <sys/timex.h>
int adjtimex (struct timex *adj);
調(diào)用adjtimex()將內(nèi)核時間相關(guān)參數(shù)讀取到adj指向的timex結(jié)構(gòu)中币旧。\
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 <unistd.h>
unsigned int sleep (unsigned int seconds);
Sleeping with Microsecond Precision
/* BSD version */
#include <unistd.h>
void usleep (unsigned long usec);
/* SUSv2 version */
#define _XOPEN_SOURCE 500
#include <unistd.h>
int usleep (useconds_t usec);
errno = 0;
usleep (1000);
if (errno)
perror ("usleep");
Sleeping with Nanosecond Resolution
#define _POSIX_C_SOURCE 199309
#include <time.h>
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 <time.h>
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 <sys/select.h>
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
就是說比如系統(tǒng)的timer ticks 是10ms, 但請求了一個1ms的sleep, 系統(tǒng)是達不到這個精度的, 所以會比期待的1ms的延時長践险,會是10ms, 會比原來長9ms。
Alternatives to Sleeping
Timers
Simple Alarms
#include <unistd.h>
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 <sys/time.h>
int getitimer (int which, struct itimerval *value);
int setitimer (int which, const struct itimerval *value,
struct itimerval *ovalue);
間隔計時器的工作方式類似于告警()吹菱,但也可以自動重新武裝自己巍虫,并在以下三種不同模式中的一種模式下操作:
- ITIMER_REAL
實時測量。當指定的實時時間已經(jīng)過去時毁葱,內(nèi)核將向進程發(fā)送一個SIGALRM信號垫言。 - ITIMER_VIRTUAL
只有在進程的用戶空間代碼正在執(zhí)行時才會減少。當指定的進程時間已過時倾剿,內(nèi)核將向進程發(fā)送SIGVTALRM筷频。 - ITIMER_PROF
進程執(zhí)行時和內(nèi)核代表進程執(zhí)行時(例如,完成系統(tǒng)調(diào)用)都會減少前痘。當指定的時間已經(jīng)過去時凛捏, 內(nèi)核向進程發(fā)送SIGPROF信號。此模式通常與ITIMER_VUALUAL耦合芹缔,以便程序能夠測量進程所花費的用戶和內(nèi)核時間坯癣。
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 <signal.h>
#include <time.h>
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 <signal.h>
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 <time.h>
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 <time.h>
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 <time.h>
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 <time.h>
int timer_delete (timer_t timerid);