定时器与超时的设置
- 一、相關時間函數
- 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結構體
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結構體
其中,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); }總結
- 上一篇: 想自学混合开发 财富值58
- 下一篇: win10宽带连接断网自动重连