linux下定時器的使用及信號操作



數據結構
  • 定時器結構:
struct itimerval
{
	struct timerval it_value;//Interval for periodic timer,從設置定時器開始到第一次定時器生效的時間
	struct timerval it_interval;//Time until next expiration,定時器生效的時間間隔
}

① 若it_value=0,系統將無視it_interval並終止定時器,因此可利用這一特性disable定時器
② 若it_interval=0,則定時器執行一次後失效

在這裏插入圖片描述

  • 時間存儲結構:
    struct timeval
    {
    	time_t tv_sec;//秒
    	suseconds_t tv_usec;//微秒(microseconds)
    }
    

定時器類型
  • ITIMER_REAL:0,自然定時,計算自然時間,實時衰減;當此計時器到期時,將發送SIGALRM信號。

  • ITIMER_VIRTUAL:1,虛擬空間計時(用戶空間),只計算進程佔用cpu的時間,進程虛擬時間中的衰減;它只在進程執行時運行;SIGVTALRM信號在到期時發送。

  • ITIMER_PROF,2,運行時計時(用戶+內核),計算佔用cpu及執行系統調用的時間,進程虛擬時間和系統代表進程運行時的衰減;它被設計用於解釋程序執行的統計分析;每次ITIMER_PROF計時器到期時,都會傳遞SIGPROF信號。

方法
  • 獲取系統時間(毫秒級)

    注意,獲得的數據從1970.01.01開始算起的

    int gettimeofday(struct timeval *,void *);
    

    如果第二個參數不爲NULL,結果不可預料

  • 設置定時器

    //參數1:定時器類型
    //參數2:指定的定時器
    //參數3:調用setitimer之前的舊定時器
    int setitimer(int,const struct itimerval *,struct itimerval *);
    // 成功返回0
    //是把你返回-1
    
  • 獲取定時器

    int getitimer(int,struct itimerval*);
    
    //example:
    getitimer(ITIMER_REAL,&value);
    
測試代碼
#include<iostream>
#include<sys/time.h>
#include<signal.h>

using namespace std;

void testFun(int a)
{
	cout<<"Hello,Linux timer~"<<endl;
}

int main()
{

    struct timeval curtime;
    gettimeofday(&curtime,NULL);
    cout<<"curtime.tv_sec:"<<curtime.tv_sec<<endl;
    cout<<"curtime.tv_usec:"<<curtime.tv_usec<<endl;
    

	struct itimerval timer;
	
	//週期定時器間隔
	timer.it_interval.tv_sec 	= 0;
	timer.it_interval.tv_usec 	=1000*500;//0.5s=500ms=500*1000us
	//從設置定時器開始到第一次定時器生效的時間
	timer.it_value.tv_sec 		=1;//1秒
	timer.it_value.tv_usec 		=0;

	setitimer(ITIMER_REAL, &timer, NULL);
	signal(SIGALRM, testFun); 	
	
	while(1);
	return 0;
}

編譯:

g++ timer_test.cpp -o timer_test

在這裏插入圖片描述

注意:tv_usec的值必須小於1000*1000,當等於1000*1000微秒時,應設置tv_sec=1,否則程序將出現未響應的狀態~



sigaction函數

頭文件:#include <signal.h>

功能:檢查或修改與指定信號相關聯的處理動作(可同時兩種動作)

//signum:指定要捕獲的信號類型
//act:指定新的信號處理方式
//oldact:輸出先前信號的處理方式,通常爲NULL
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);

數據結構:

//sa_handler:函數指針,和signal()的參數handler相同,代表新的信號處理函數,其他意義請參考signal()

//sa_sigaction:是另一個信號處理函數,有三個參數,可獲得關於信號的更詳細的信息;當 sa_flags 成員的值包含了 SA_SIGINFO 標誌時,系統將使用 sa_sigaction 函數作爲信號處理函數,否則使用 sa_handler 作爲信號處理

//sa_mask:用來指定在信號處理函數執行期間需要被屏蔽的信號,特別是當某個信號被處理時,它自身會被自動放入進程的信號掩碼,因此在信號處理函數執行期間這個信號不會再度發生。

//sa_flags:用來設置信號處理的其他相關操作
//			SA_RESETHAND:當調用信號處理函數時,將信號的處理函數重置爲缺省值SIG_DFL
//			SA_RESTART:如果信號中斷了進程的某個系統調用,則系統自動啓動該系統調用(使被信號打斷的系統調用自動重新發起)
//			SA_NODEFER :一般情況下, 當信號處理函數運行時,內核將阻塞該給定信號。但是如果設置了 SA_NODEFER標記, 那麼在該信號處理函數運行時,內核將不會阻塞該信號(使對信號的屏蔽無效,即在信號處理函數執行期間仍能發出這個信號)
//			SA_NOCLDSTOP:使父進程在它的子進程暫停或繼續運行時不會收到 SIGCHLD 信號。
//			SA_NOCLDWAIT:使父進程在它的子進程退出時不會收到 SIGCHLD 信號,這時子進程如果退出也不會成爲殭屍進程。
//			SA_SIGINFO:使用 sa_sigaction 成員而不是 sa_handler 作爲信號處理函數。


//sa_restorer:此參數未使用,據說已廢棄

 struct sigaction
 {
	  void     (*sa_handler)(int);
	  void     (*sa_sigaction)(int, siginfo_t *, void *);
	  sigset_t  sa_mask;
	  int       sa_flags;
	  void     (*sa_restorer)(void);
 };

測試代碼:
        具體看這篇博文→https://www.cnblogs.com/Jacket-K/p/8364874.html

其他結論
  1. 默認情況下,信號將由主進程接收處理,就算信號處理函數是由子線程註冊的
  2. 對信號的處理是進程中所有的線程共享的














參考文獻:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章