- 一、相关时间函数
- 1. gettimeofday()
- 2. time()
- 3. clock()
- 二、间隔定时器
- 1. setitimerval()
- 2. getitimerval()
- 3. 实时定时器的使用
- 三、为阻塞操作设置超时
- 1. alarm()
- 2. 给read()设置读超时
- 一、相关时间函数
一、相关时间函数
1. gettimeofday()
获取日历时间。
#include <sys/time.h>int gettimeofday(struct timeval *tv, struct timezone *tz);
- timeval结构体
struct timeval {time_t tv_sec; // 秒suseconds_t tv_usec; // 微秒(long int)
};
2. time()
返回自Epoch(格林威治标准时间1970.01.01 0:00AM)以来的秒数。
#include <time.h>time_t time(time_t *timep);
参数timep存储返回的时间。若timep为空,则直能从函数返回值获得。
time_t t = time(NULL);
3. clock()
计时函数。返回值为从程序启动到调用该函数所占用CPU的时间,实际为CPU时钟计时单元(clock tick)数。
#include <time.h>clock_t clock(void) ;
由于不同系统或编译器对于每秒的时钟单元数定义不同,所以直接输出会有所不同。所以还定义了常量CLOCKS_PER_SEC,表示一秒钟会有多少个时钟计时单元,其定义如下:
#define CLOCKS_PER_SEC ((clock_t)1000)
CLOCKS_PER_SEC在Linux 4.15.0-32-generic
系统上数值为1000000。
二、间隔定时器
1. setitimerval()
使用系统调用setitimer()
来创建间隔定时器,这种定时器会在一定时间后到期,并可以在到期后每隔一段时间到期一次。
#include <sys/time.h>int setitimer(int which, const struct itimerval *new_value,struct itimerval *old_value);
which参数的可选项:
ITIMER_REAL
以真实时间计时,到期产生SIGALARM信号ITIMER_VIRTUAL
以虚拟时间(用户模式下CPU时间)计时ITIMER_PROF
创建profiling定时器以内核态与用户态CPU时间总和计时,到期会产生SIGPROF信号
itimerval结构体
struct itimerval {struct timeval it_interval; // 间隔定时器的间隔时间struct timeval it_value; // 定时器到期的剩余时间
};
其中,it_value表示距离定时器到期的剩余时间,it_interval记录定时器的周期时间(或不进行周期性定时,it_interval中两个值同为0时表示没有周期性定时,即一次性定时器)。若进行周期性定时,则在每次到时后会将it_interval重新存储倒计时的间隔时间。
2. getitimerval()
获取定时器当前状态。
#include <sys/time.h>int getitimerval(int which, struct itimerval *curr_value );
curr_value存储定时器当前状态,其内容与调用setitimerval()返回的old_value内容相同。
3. 实时定时器的使用
/* 运行说明:./timer 1 800000 1 0第二个参数为倒计时的秒数,第三个参数为倒计时的微秒数,第四个参数为定时器间隔时间的秒数,第五个参数为定时器间隔时间的微秒数后四个参数可以省略,默认为 2 0 0 0
*/#include <iostream>
#include <string.h>
#include <sys/time.h>
#include <signal.h>static volatile sig_atomic_t gotAlam = 0;/* 打印时间,includeTimer表示是否为第一次打印,第一次只打印前两个数字 */
static void displayTimes( const char *msg, bool includeTimer ) {struct itimerval itv;static struct timeval start; // 起始状态struct timeval curr; // 当前状态static int callNum = 0; // 当前函数被调用次数if( callNum == 0 ) {if( gettimeofday( &start, nullptr ) == -1 ) {perror( "gettimeofday" );}}/* 每20行打印一次提示信息 */if( callNum % 20 == 0 ) {printf(" Elapsed Value Interval\n");}if( gettimeofday( &curr, NULL ) == -1 ) {perror( "gettimeofday" );}printf("%-7s %6.2f", msg, curr.tv_sec - start.tv_sec + (curr.tv_usec - start.tv_usec) / 1000000.0 );/* 可以打印后两个数字 */if( includeTimer ) {if( getitimer( ITIMER_REAL, &itv ) == -1 ) {perror( "getitimer" );}printf(" %6.2f %6.2f", itv.it_value.tv_sec + itv.it_value.tv_usec / 1000000.0, itv.it_interval.tv_sec + itv.it_interval.tv_usec / 1000000.0);}printf("\n");callNum++;
}/* 信号处理函数 */
static void sigalrmHandler( int sig ) {gotAlam = 1;
}int main( int argc, char **argv ) {struct itimerval itv;clock_t preClock;int maxSigs = 0; // 信号触发最大次数int sigCnt = 0; // 信号已触发次数struct sigaction sa;sigemptyset( &sa.sa_mask );sa.sa_flags = 0;sa.sa_handler = sigalrmHandler;if( sigaction( SIGALRM, &sa, NULL ) == -1 ) {perror( "sigaction" );}maxSigs = ( itv.it_interval.tv_sec == 0 && itv.it_interval.tv_usec == 0 ) ? 1 : 3;displayTimes( "start:", false );itv.it_value.tv_sec = (argc > 1) ? atoi( argv[1] ) : 2;itv.it_value.tv_usec = (argc > 2) ? atoi( argv[2] ) : 0;itv.it_interval.tv_sec = (argc > 3) ? atoi( argv[3] ) : 0;itv.it_interval.tv_usec = (argc > 4) ? atoi( argv[4] ) : 0;if( setitimer( ITIMER_REAL, &itv, 0 ) == -1 ) {perror( "setitimer" );}preClock = clock();while( true ) {while( ( clock() - preClock ) * 10 / CLOCKS_PER_SEC < 5 ) {/* 定时器时间到 */if( gotAlam ) {gotAlam = false;displayTimes( "ALARM:", true );sigCnt++;if( sigCnt >= maxSigs ) {printf("That's all folk\n");exit( EXIT_SUCCESS );}}}preClock = clock();displayTimes( "Main:", true );}
}
三、为阻塞操作设置超时
1. alarm()
创建一次性实时定时器。
#include <unistd.h>unsigned int alarm(unsigned int seconds);
seconds表示倒计时的秒数。到期后会发送SIGALARM信号。
调用alarm(0)可以屏蔽所有现有定时器。
2. 给read()设置读超时
#include <iostream>
#include <string.h>
#include <sys/time.h>
#include <signal.h>
#include <unistd.h>
using namespace std;const int BUFFER_SIZE = 200;/* 信号处理函数 */
static void handler( int sig ) {printf("caught signal\n");
}int main( int argc, char **argv ) {struct sigaction sa;char buf[BUFFER_SIZE];ssize_t numRead;int savedErrno;sa.sa_flags = ( argc > 2 ) ? SA_RESTART : 0;sigemptyset( &sa.sa_mask );sa.sa_handler = handler;if( sigaction( SIGALRM, &sa, NULL ) == -1 ) {perror("sigaction");}/* 设置倒计时 */alarm( (argc > 1) ? atoi(argv[1]) : 10 );numRead = read( STDIN_FILENO, buf, BUFFER_SIZE - 1 );savedErrno = errno;alarm(0); // 将现有定时器屏蔽errno = savedErrno;if( numRead == -1 ) {if( errno == EINTR ) { // read系统调用被信号打断,即收到超时信号printf("Read timed out\n");} else {perror("read");}} else { // 未超时printf("Successful read %ld bytes : %.*s", long(numRead), int(numRead), buf);}exit(EXIT_SUCCESS);
}