赞
踩
long hz;
hz = sysconf (_SC_CLK_TCK);
printf(“system timer is %ld\n”,hz);
1.2 POSIX时钟:
CLOCK_MONOTONIC:线性增长时间
CLOCK_REALTIME:墙上时间
CLOCK_PROCESS_CPUTIME_ID:进程占用CPU时间
CLOCK_THREAD_CPUTIME_ID:线程占用CPU时间
API:
int clock_getres (clockid_t clock_id, struct timespec *res);
1.3 时钟API比较
GETTIME SETTIME RESOLUTION CLOCK_TYPE
time() stime() second system clock
gettimeofday() settimeofday() us system clock
clock_gettime() clock_settime() ns posix clock
2.睡眠API
usleep()微妙级精度睡眠
nanosleep()纳秒级精度睡眠
clock_nanosleep()符合POSIX标准,为最高级的睡眠调用
select 可移植睡眠实现
3.定时器API
3.1 间歇定时器
#include <sys/time.h>
int getitimer (int which, struct itimerval *value);
int setitimer (int which, const struct itimerval *value, struct itimerval *ovalue);
3.2 posix定时器
#include <signal.h>
#include <time.h>
int timer_create (clockid_t clockid, struct sigevent *evp, timer_t *timerid);
int timer_settime (timer_t timerid,
int flags,
const struct itimerspec *value,
struct itimerspec *ovalue);
int timer_gettime (timer_t timerid, struct itimerspec *value);
int timer_getoverrun (timer_t timerid);
int timer_delete (timer_t timerid);
进程消耗的时间,包含用户空间代码占用时间和内核在该进程中消耗的时间
时间源严格线性增长。
单调时间的重要性不在于当前值,而是在于保证时间源线性增长
用来计算两次时间采样的差值
墙上时间用于衡量绝对时间
单调时间用于计算相对时间
进程时间用于测量进程在运行过程中占用CPU的时间
Unix系统使用大纪元(定义为1970年1月1日00:00:00)以来经过的秒数
表示绝对时间
软件时钟是由内核维护的时钟,操作系统通过软件时钟来追踪时间进程。
内核初始化一个遵循特定频率的周期计时器,一般称之为系统计时器(system )
当一个计时器间隔结束时,内核将消耗时间增加一个单位,称之为一个tick或者jiffy
linux中的系统定时器频率称之为HZ
posix定义运行时确定系统计时器频率的方式
long hz;
hz = sysconf (_SC_CLK_TCK);
printf("system timer is %ld\n",hz);
high resolution timers:高分辨率定时器
表示大纪元以来已流逝的秒数
定义在头文件<time.h>
typedef long time_t;
毫秒级精度
定义在头文件<sys/time.h>
struct timeval {
time_t tv_sec;//seconds
suseconds_t tv_usec;//microseconds 通常为整型
};
纳秒级精度
定义在头文件<time.h>
struct timespec {
time_t tv_sec;//seconds
long tv_nsec;//nanoseconds [0 … 999999999]
};
注意:纳秒级或毫秒级精度是时间数据结构所能表示的精度
但是,在实际使用过程中,系统计时器可能无法实现这个精度
在函数中尽量采用可用的高精度时间数据结构,这样可以利用系统所提供的各种精度
定义在头文件<time.h>
struct tm {
int tm_sec; /* seconds 0~59 /
int tm_min; / minutes 0~59 /
int tm_hour; / hours 0~23 /
int tm_mday; / the day of the month 1~31 /
int tm_mon; / the month 0~11 /
int tm_year; / the year 从1900年以来的年数*/
int tm_wday; /* the day of the week 0~6*/
int tm_yday; /* the day in the year 0~365*/
//以下变量暂无实用价值
int tm_isdst; /* daylight savings time /
#ifdef _BSD_SOURCE
long tm_gmtoff; / time zone’s offset from
GMT */
const char tm_zone; / time zone
abbreviation /
#endif / _BSD_SOURCE */
};
CLOCK_MONOTONIC:线性增长时钟
CLOCK_REALTIME:系统级真实时间(墙上时间)
CLOCK_PROCESS_CPUTIME_ID:处理器分配给每个进程的高精度时钟
CLOCK_THREAD_CPUTIME_ID:类似进程时钟,处理器分配给每个线程的高精度时钟
POSIX定义了四个时钟源,但只有CLOCK_REALTIME是必须实现的
因此,可移植的代码只使用CLOCK_REALTIME
#include <time.h>
int clock_getres (clockid_t clock_id, struct timespec *res);
示例:获取POSIX时钟的时钟源
struct timespec ts_1; clockid_t clocks[] = { CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID, (clockid_t) -1 }; for (i = 0; clocks[i] != (clockid_t) -1; i++) { ret = clock_getres(clocks[i], &ts_1); if (ret) perror("clock_getres"); else printf("clock = %d sec = %ld nsec = %ld\n", clocks[i], ts_1.tv_sec, ts_1.tv_nsec); }
$ ./a.out
clock = 0 sec = 0 nsec = 10000000 //10ms
clock = 1 sec = 0 nsec = 10000000 //10ms
clock = 2 sec = 0 nsec = 1
clock = 3 sec = 0 nsec = 1
CLOCK_REALTIME 和 CLOCK_MONOTONIC都和系统定时器精度有关
CLOCK_PROCESS_CPUTIME_ID 和CLOCK_THREAD_CPUTIME_ID和
TSC(Time Stamp Counter, N纳秒级精度)有关
#include <time.h>
time_t time (time_t *t);
time_t忽略了闰秒,认为被4整除的年份都是闰年
time_t表示法的要点不在于精确,在于一致。
#include <sys/time.h>
int gettimeofday (struct timeval *tv, struct timezone *tz);
第二个参数忽略
示例:
int ret;
struct timeval tv;
ret = gettimeofday(&tv, NULL);
if (ret)
perror("gettimeofday");
else
printf("seconds=%ld useconds=%ld\n",
(long) tv.tv_sec, (long) tv.tv_usec);
#include <time.h>
int clock_gettime (clockid_t clock_id, struct timespec *ts);
示例:
clockid_t clocks[] = { CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID, (clockid_t) -1 }; struct timespec ts_1; for (i = 0; clocks[i] != (clockid_t) -1; i++) { ret = clock_gettime(clocks[i], &ts_1); if (ret) perror("clock_getres"); else printf("clock = %d sec = %ld nsec = %ld\n", clocks[i], ts_1.tv_sec, ts_1.tv_nsec); } int sum = 0; i = 4 * 10^8; while(--i > 0) { sum += i; } for (i = 0; clocks[i] != (clockid_t) -1; i++) { ret = clock_gettime(clocks[i], &ts_1); if (ret) perror("clock_getres"); else printf("clock = %d sec = %ld nsec = %ld\n", clocks[i], ts_1.tv_sec, ts_1.tv_nsec); }
$ ./a.out
clock = 0 sec = 94546 nsec = 530000000
clock = 1 sec = 94546 nsec = 530000000
clock = 2 sec = 0 nsec = 10000000
clock = 3 sec = 0 nsec = 10000000
clock = 0 sec = 94564 nsec = 30000000
clock = 1 sec = 94564 nsec = 30000000
clock = 2 sec = 17 nsec = 510000000
clock = 3 sec = 17 nsec = 510000000
#include <sys/times.h>
struct tms {
clock_t tms_utime; /* user time consumed /
clock_t tms_stime; / system time consumed /
clock_t tms_cutime; / user time consumed by children /
clock_t tms_cstime; / system time consumed by children */
};
clock_t times (struct tms *buf);
示例:
struct tms process_timer; times(&process_timer); printf("process timer:tms_utime %d\n", process_timer.tms_utime); printf("process timer:tms_stime %d\n", process_timer.tms_stime); printf("process timer:tms_cutime %d\n", process_timer.tms_cutime); printf("process timer:tms_cstime %d\n", process_timer.tms_cstime); i = 400000000; while(--i > 0) { sum += i; } printf("hello times() which is in <sys/time!s!.h>\n"); times(&process_timer); printf("process timer:tms_utime %d\n", process_timer.tms_utime); printf("process timer:tms_stime %d\n", process_timer.tms_stime); printf("process timer:tms_cutime %d\n", process_timer.tms_cutime); printf("process timer:tms_cstime %d\n", process_timer.tms_cstime);
$: ./a.out
process timer:tms_utime 0
process timer:tms_stime 0
process timer:tms_cutime 0
process timer:tms_cstime 0
hello times() which is in <sys/time!s!.h>
process timer:tms_utime 1750 //unit:tick. current val equal 10ms
process timer:tms_stime 0
process timer:tms_cutime 0
process timer:tms_cstime 0
#include <time.h>
int stime (time_t *t);
与time()相对应
#include <sys/time.h>
int settimeofday (const struct timeval *tv, const struct timezone *tz);
与gettimeofday()相对应, 微妙级精度
#include <time.h>
int clock_settime (clockid_t clock_id, const struct timespec *ts);
与clock_gettime()相对应, 纳秒级精度
#include <sys/time.h>
int adjtime (const struct timeval *delta, struct timeval *olddelta);
绝对时间发生改变
而相对时间不改变
机制是:调整时钟改变的速度
#include <unistd.h>
unsigned int sleep (unsigned int seconds);
秒级精度
示例:
unsigned int s = 5;
while ((s = sleep (s)))
;
/* BSD version /
#include <unistd.h>
void usleep (unsigned long usec);
/ SUSv2 version */
#define _XOPEN_SOURCE 500
#include <unistd.h>
int usleep (useconds_t usec);
为了提高可移植性,假设参数为无符号整型,并且不能依赖其返回值
示例:
unsigned int usecs = 200;
usleep (usecs);
#include <time.h>
int nanosleep (const struct timespec *req, struct timespec *rem);
示例:
struct timespec req = { .tv_sec = 1, .tv_nsec = 0 };
struct timespec rem, *a = &req, *b = &rem;
struct timespec *tmp = a;
/* sleep for 1s */
while (nanosleep (a, b) && errno == EINTR) {
a = b;
b = tmp;
}
优点:
纳秒级精度
符合POSIX.1b标准
实现无需信号
#include <time.h>
int clock_nanosleep (clockid_t clock_id,
int flags,
const struct timespec *req,
struct timespec *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");
//绝对睡眠
struct timespec ts;
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”);
如果程序对时间的要求不严格,可采用相对睡眠,
如果程序对时间的要求严格,可采用绝对睡眠,以此避免潜在的竞争条件
void milliseconds_sleep(unsigned long ms)
{
int err;
struct timeval tv;
tv.tv_sec = ms/1000;
tv.tv_usec = (ms%1000)*1000;
do{
err = select(0,NULL,NULL,NULL,&tv);
}while(err<0 && errno==EINTR);
}
原因1:调度行为
原因2:定时器的粒度较大
如果可能的话,尽量避免使用睡眠
使用睡眠忙等待事件发生是糟糕的设计
应使用在文件描述符上阻塞,允许内核处理睡眠和唤醒进程的代码
内核提供了在一定时间后通知进程的机制。
定时器超时所需的时间叫做延迟(delay),或者叫做超时值(expiration)
#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 ();
}
#include <sys/time.h>
int getitimer (int which, struct itimerval *value);
int setitimer (int which, const struct itimerval *value, struct itimerval *ovalue);
#include <signal.h>
#include <time.h>
int timer_create (clockid_t clockid, struct sigevent *evp, timer_t *timerid);
建立一个与POSIX时钟clockid相关联的新定时器
clockid_t clockid: 指定POSIX时钟
CLOCK_REALTIME,
CLOCK_MONOTONIC,
CLOCK_PROCESS_CPUTIME_ID
CLOCK_THREAD_CPUTIME_ID,
struct sigevent *evp:定义了定时器到期时的异步通知方式
若evp == NULL, sigev_notify为SIGEV_SIGNAL
sigev_signo为SIGALRM
sigev_val为定时器ID
#include <signal.h>
struct sigevent {
union sigval sigev_value;
int sigev_signo;
int sigev_notify;
//SIGEV_NONE
//SIGEV_SIGNAL:发送sigev_signo信号给进程
//SIGEV_THREAD:在当前进程创建新线程,
// 执行sigev_notify_function函数
// 参数为sigev_value
// sigev_notify_attributes为线程属性
void (*sigev_notify_function)(union sigval);
pthread_attr_t *sigev_notify_attributes;
};
union sigval {
int sival_int;
void *sival_ptr;
};
timer_t *timerid:定时器ID
#include <time.h>
int timer_settime (timer_t timerid,
int flags,
const struct itimerspec *value,
struct itimerspec *ovalue);
设置timerid指定的定时器的过期时间为value
struct itimerspec {
struct timespec it_interval; /* next value /
struct timespec it_value; / current value */
};
struct itimerspec *value:
it_value指定了定时器的过期时间。
it_interval指定了定时器的重载时间
当定时器过期时,使用it_interval的值更新it_value
如果it_interva == 0,定时器在it_value过期后停止运行
int flags:
TIMER_ABSTIME:it_value指定的时间为绝对时间
0:it_value指定的时间为相对时间
struct itimerspec *ovalue:
存储之前定时器的设置
#include <time.h>
int timer_gettime (timer_t timerid, struct itimerspec *value);
#include <time.h>
int timer_getoverrun (timer_t timerid);
确定定时器有无超限
示例:
ret = timer_getoverrun (timer2);
if (ret == -1)
perror ("timer_getoverrun");
else if (ret == 0)
printf ("no overrun\n");
else
printf ("%d overrun(s)\n", ret);
#include <time.h>
int timer_delete (timer_t timerid);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。