linux上点时间延时,Linux上时间和定时器
Linux下時間和定時器
http://blog.chinaunix.net/u1/35065/showart_1870601.html重點讀了第三種方法。文章寫得很好,加了一點點注釋可參考http://linux.die.net/man/3/timer_settime
http://linux.die.net/man/2/setitimer
http://opengroup.org/onlinepubs/007908799/xsh/timer_settime.html
秒---毫秒---微秒---納秒(數量級:1000)
一、問題的提出我們開發程序時,經常會遇到時間和定時器的問題,為了更好的使用時間和定時器,現在列舉一個一些時間結構體、函數和定時器。
二、解決思路1.時間類型1) time_t是一個長整型,一般用來表示用1970年以來的秒數。
2)struct timeval有兩個成員,一個是秒,一個是微妙。
struct timeval
{
long tv_sec;??????? /* seconds */
long tv_usec;?? /* microseconds */
};
3) struct timespec有兩個成員,一個是秒,一個是納秒。
struct timespec
{
time_t tv_sec;????????? /* seconds */
long??? tv_nsec;??????? /* nanoseconds */
};
4) struct tm是直觀意義上的時間表示方法
struct tm
{
int???? tm_sec;???????? /* seconds */
int???? tm_min;???????? /* minutes */
int???? tm_hour;??????? /* hours */
int???? tm_mday;???????? /* day of the month */
int???? tm_mon;???????? /* month */
int???? tm_year;??????? /* year */
int???? tm_wday;???????? /* day of the week */
int???? tm_yday;??????? /* day in the year */
int???? tm_isdst;??????? /* daylight saving time */
};
5)
struct timeb
{
time_t??? time;??????????? //從1970來經過的秒數unsigned short millitm; //毫秒short???? timezone;??????? //時區short???? dstflag;//為日光節約時間的修正值,如果為非0代表啟用日光節約修正};
6)
struct timezone
{
int tz_minuteswest;//和格林尼治時間相差多少分int tz_dsttime;//日光節約時間的狀態};
日光節約時間:夏時制。
2.時間函數1) char *asctime(const struct tm *timeptr)
將時間和日期以字符串格式顯示。
2)clock_t clock(void)
取得進程占用cpu的大約時間。
3)char *ctime(const time_t *timep)
將時間和日期以字符串格式顯示。
4) double difftime(time_t time1, time_t time0)
計算時間time1和time0間的差距。
5) int ftime(struct timeb *tp)
取得目前的時間和日期。
6) int gettimeofday(struct timeval *tv, struct timezone *tz)
取得目前的時間。
7)strcut tm *gmtime(const time_t *timep)
time_t結構時間轉tm結構時間,tm為UTC時區。
8) struct tm *localtime(const time_t *timep)
將time_t結構時間轉tm結構時間,tm是當地時區。
9)time_t mktime(struct tm *timeptr)
將tm結構時間轉換為time_t。
10) int settimeofday(const struct timeval *tv, const struct timezone *tz)
設置時間為tv,設置時區為tz。
11) size_t strftime(char *s, size_t max, const char *format, const struct tm *tm)
將參數tm的時間結構依照參數format所指定的字符串格式做轉換,轉換后的字符串將復制到參數s所指的字符串數組中,該字符串的最大長度為參數max所控制。
12) time_t time(time_t *t)
取得目前的時間,時間按照UTC。
13) void tzset(void)
從環境變量TZ取得目前當地的時間。
3.延遲函數主要的延遲函數有:sleep(),usleep(),nanosleep(),select(),pselect().
1) unsigned int sleep(unsigned int seconds)
延時seconds秒。
2) void usleep(int micro_seconds)
延時micro_seconds微妙
3) int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
延時的時間為rqtp,如果nansleep被信號中斷,且rmtp不為NULL,則rmtp指定的位置上包含的就是剩余時間。
4) int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
如果將readfds, writefds, exceptfds置為NULL,timeout為非零,則延時timeout。
5) int pselect(int maxfdp1, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec tsptr, const sigset_t *sigmask)
如果將readfds, writefds, exceptfds置為NULL,tsptr為非零,則延時tsptr。
3.定時器1) unsigned int alarm(unsigned int seconds)
設置一個定時器,在seconds秒后超時,當定時器超時時,產生SIGALRM信號。如果不忽略或不捕捉此信號,則其默認動作是終止調用該alarm函數的進程,如果設置了SIGALRM信號處理函數,則會執行該信號處理函數。
每個進程只能有一個鬧鐘時鐘。如果在調用alarm時,以前已為該進程設置過鬧鐘時鐘,而且它還沒有超時,則將該鬧鐘時鐘的余留值作為本次alarm函數調用的值返回,以前登記的鬧鐘時鐘則被新值代替。
例子:
void sigalrm_fn(int sig)
{
printf("alarm!\n");
alarm(2);
return;
}
int main(void)
{
signal(SIGALRM, sigalrm_fn);
alarm(1);
while(1) pause();
}
2) POSIX:XSI間隔定時器
int getitimer(int which, struct itimerval *value);
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);
struct itimerval
{
struct timeval it_interval; /*計時器重啟動的間歇值*/
struct timeval it_value;??? /*計時器安裝后首先啟動的初始值*/
};
getitimer()用計時器的當前值填寫value指向的結構體。setitimer()將value指向的結構體設為計時器的當前值,如果ovalue不是NULL,將返回計時器原有值。
which:間歇計時器類型,有三種選擇:
l???????? ITIMER_REAL //數值為0,計時器的值實時遞減,發送的信號是SIGALRM。
l???????? ITIMER_VIRTUAL //數值為1,進程執行時遞減計時器的值(虛擬時間),發送的信號是SIGVTALRM。
l???????? ITIMER_PROF //數值為2,虛擬時間和進程的系統時間遞減,發送的信號是SIGPROF。
itimerval結構中的it_value是減少的時間,當這個值為0的時候就發出相應的信號了.然后再將it_value設置為it_interval值.也就是先處理it_value中設置的值,為0后發送信號(根據which來判斷發送什么信號),之后都是根據it_interval的值發送信號。若it_value和it_interval都為0,也就沒有相應的信號產生了。
和alarm()一樣,由于信號的限制,POSIX:XSI間隔定時器對于每個進程來說最多只有3個定時器。
例子:
void sigroutine(int signo)
{
switch (signo)
{
case SIGALRM:
printf("Catch a signal -- SIGALRM \n");
signal(SIGALRM, sigroutine);
break;
case SIGVTALRM:
printf("Catch a signal -- SIGVTALRM \n");
signal(SIGVTALRM, sigroutine);
break;
}
return;
}
int main()
{
struct itimerval value, ovalue, value2;
sec = 5;
printf("process id is %d\n", getpid());
signal(SIGALRM, sigroutine);
signal(SIGVTALRM, sigroutine);
value.it_value.tv_sec = 1;
value.it_value.tv_usec = 0;
value.it_interval.tv_sec = 1;
value.it_interval.tv_usec = 0;
setitimer(ITIMER_REAL, &value, &ovalue);
value2.it_value.tv_sec = 0;
value2.it_value.tv_usec = 500000;
value2.it_interval.tv_sec = 0;
value2.it_interval.tv_usec = 500000;
setitimer(ITIMER_VIRTUAL, &value2, &ovalue);
for(;;)
;
}
3)POSIX:TMR間隔定時器
int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid)
進程可以通過調用timer_create()創建特定的定時器,定時器是每個進程自己的,不是在fork時繼承的。timer_create的參數clock_id說明定時器是基于哪個時鐘的,*timerid裝載的是被創建的定時器的ID。timer_create函數創建了定時器,并將他的ID放入timerid指向的位置中。參數evp指定了定時器到期要產生的異步通知。如果evp為NULL,那么定時器到期會產生默認的信號,對CLOCK_REALTIMER來說,默認信號就是SIGALRM。對那些定時器到期時要產生除默認信號之外的其它信號的定時器來說,程序必須將evp->sigev_signo設置為期望的信號碼。struct sigevent結構中的成員evp->sigev_notify說明了定時器到期時應該采取的行動。通常,這個成員的值為SIGEV_SIGNAL,這個值說明在定時器到期時,會產生一個信號。程序可以將成員evp->sigev_notify設為SIGEV_NONE來防止定時器到期時產生信號。
如果幾個定時器產生了同一個信號,處理程序可以用evp->sigev_value來區分是哪個定時器產生了信號。要實現這種功能,程序必須在為信號安裝處理程序時,使用struct sigaction的成員sa_flags中的標志符SA_SIGINFO。
clock_id的取值為以下:
CLOCK_REALTIME :Systemwide realtime clock.
CLOCK_MONOTONIC:Represents monotonic time. Cannot be set.
CLOCK_PROCESS_CPUTIME_ID :High resolution per-process timer.
CLOCK_THREAD_CPUTIME_ID :Thread-specific timer.
CLOCK_REALTIME_HR :High resolution version of CLOCK_REALTIME.
CLOCK_MONOTONIC_HR :High resolution version of CLOCK_MONOTONIC.
struct sigevent
{
int sigev_notify; //notification type
int sigev_signo; //signal number
union sigval?? sigev_value; //signal value
void (*sigev_notify_function)(union sigval);
pthread_attr_t *sigev_notify_attributes;
}
union sigval
{
int sival_int; //integer value
void *sival_ptr; //pointer value
}
通過將evp->sigev_notify設定為如下值來定制定時器到期后的行為:
l???????? SIGEV_SIGNAL:發送由evp->sigev_sino指定的信號到調用進程,evp->sigev_value的值將被作為siginfo_t結構體中si_value的值。
l???????? SIGEV_NONE:什么都不做,只提供通過timer_gettime和timer_getoverrun查詢超時信息。
l???????? SIGEV_THREAD:以evp->sigev_notification_attributes為線程屬性創建一個線程,在新建的線程內部以evp->sigev_value為參數調用evp->sigev_notification_function。
int timer_delete(timer_t timerid);
刪除ID為timerid的POSIX:TMR定時器。
int timer_settime(timer_t timerid,int flags,const struct itimerspec *value,struct itimerspec *ovalue);
struct???? itimerspec{struct???? timespec?? it_interval; //定時器周期值struct???? timespec?? it_value;???? //定時器到期值};
timer_settime負責啟動或停止timer_create創建的定時器。參數flag說明定時器使用的是相對時間還是絕對時間。相對時間與POSIX:XSI定時器使用的策略類似,而絕對時間的精確度更高。參數vaule指向的值來設置timerid指定的定時器。如果ovalue不為NULL,timer_settime就將定時器以前的值放在ovalue指定的位置上。如果定時器正在運行,那么*ovalue的成員it_value非零,并包含了定時器到期之前剩余的時間。
TIMER_ABSTIME表示絕對時間;如果flag沒有設定為TIMER_ABSTIME,則定時器從調用開始在it_value內超時;即value->it_value代表計時器第一次超時的時間。如果設定為TIMER_ABSTIME,該函數表現為時間直到下一次超時被設定為it_value指定的絕對時間和與timerid相聯的時鐘值的差值。如果已經到了it_value指定的值,那么超時后的處理就會立即執行。定時器的再裝由value的it_interval成員值來設定。
int timer_gettime(timer_t timerid,struct itimerspec *value);
獲得一個活動定時器的剩余時間。
int timer_getoverrun(timer_t timerid);
有可能一個定時器到期了,而同一定時器上一次到期時產生的信號還處于掛起狀態。在這種情況下,其中的一個信號可能會丟失。這就是定時器超限。程序可以通過調用timer_getoverrun來確定一個特定的定時器出現這種超限的次數。定時器超限只能發生在同一個定時器產生的信號上。由多個定時器,甚至是那些使用相同的時鐘和信號的定時器,所產生的信號都會排隊而不會丟失。
例子:
編譯方法:
gcc -o example example.c?? -lrt?? -lpthread
那個rt庫就是POSIX?? realtime?? extension的庫。
#include??
#include??
#include?? #include?? //不然會出現對memset函數的警告
void
handle?? (union sigval?? v)
{
time_t?? t;
char?? p[32];
time?? (&t);
strftimep,?? sizeof?? (p),?? "%T",?? localtime?? (&t));
printf("%s?? thread?? %lu,?? val?? =?? %d,?? signal?? captured.\n",?? p,?? pthread_self(), v.sival_int);
return;
}
int create?? (int?? seconds,?? int?? id)
{
timer_t?? tid;
struct?? sigevent?? se;
struct?? itimerspec?? ts,?? ots;
memset?? (&se,?? 0,?? sizeof?? (se));
se.sigev_notify?? =?? SIGEV_THREAD;
se.sigev_notify_function?? =?? handle;
se.sigev_value.sival_int?? =?? id;?? //作為handle()的參數
if?? (timer_create?? (CLOCK_REALTIME,?? &se,?? &tid)??
{
perror?? ("timer_creat");
return?? -1;
}
puts?? ("timer_create?? successfully.");
ts.it_value.tv_sec?? =?? 3;
ts.it_value.tv_nsec?? =?? 0;
ts.it_interval.tv_sec?? =?? seconds;
ts.it_interval.tv_nsec?? =?? 0;
if?? (timer_settime (tid,?? TIMER_ABSTIME,?? &ts,?? &ots)??
{
perror?? ("timer_settime");
return?? -1;
}
return?? 0;
}
int?? main?? (void)
{
create?? (3,?? 1);
create?? (5,?? 2);
for?? (;;)
{
sleep?? (10);
}
}
三、總結Linux下定時器主要使用上面介紹的三種定時器。
總結
以上是生活随笔為你收集整理的linux上点时间延时,Linux上时间和定时器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: qt构建json字符串的时候,某一个值为
- 下一篇: Linux进程核心代码怎么查看,GCOV