在進行堵塞式系統呼叫時。為避免程式陷入無限期的等待,能夠為這些堵塞式系統呼叫設定定時器。Linux提供了alarm系統呼叫和SIGALRM訊號實現這個功能。
要使用定時器。首先要安裝SIGALRM訊號。假設不安裝SIGALRM訊號,則程式收到SIGALRM訊號後。預設的動作就是終止當前程式。
SIGALRM訊號成功安裝後,在什麼情況下程式會收到該訊號呢?這就要依賴於Linux提供的定時器功能。在Linux系統下,每一個程式都有惟一的一個定時器,該定時器提供了以秒為單位的定時功能。在定時器設定的超時時間到達後,呼叫alarm的程式將收到SIGALRM訊號。
alarm系統呼叫的原型為:
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
引數說明:
1)seconds:要設定的定時時間,以秒為單位。在alarm呼叫成功後開始計時。超過該時間將觸發SIGALRM訊號。
返回值:
返回當前程式曾經設定的定時器剩餘秒數。
例8-10:程式設計利用SIGALRM訊號實現秒定時器。
程式碼例如以下:
#include <stdio.h>
#include <signal.h>
//全域性計數器變數
int Cnt=0;
//SIGALRM訊號處理函式
void CbSigAlrm(int signo)
{
//輸出定時提示資訊
printf(" seconds: %d",++Cnt);
printf("\r");
//又一次啟動定時器,實現1秒定時
alarm(1);
}
void main()
{
//安裝SIGALRM訊號
if(signal(SIGALRM,CbSigAlrm)==SIG_ERR)
{
perror("signal");
return;
}
//關閉標準輸出的行快取模式
setbuf(stdout,NULL);
//啟動定時器
alarm(1);
//程式進入無限迴圈,僅僅能手動終止
while(1)
{
//暫停,等待訊號
pause();
}
}
8.5.2 SIGCLD訊號
在Linux的多程式程式設計中,SIGCLD是一個很重要的訊號。當一個子程式退出時。並非馬上釋放其佔用的資源,而是通知其父程式,由父程式進行興許的工作。
在這一過程中,系統將依次產生下列事件。
1)向父程式傳送SIGCLD訊號,子程式進入zombie(殭屍)狀態。
2)父程式接收到SIGCLD訊號,進行處理。
假設在上述過程中父程式既沒有忽略SIGCLD訊號。也未捕獲該訊號進行處理,則子程式將進入殭屍狀態。殭屍狀態的程式不能被作業系統呼叫,也沒有不論什麼可執行程式碼,它只是是佔用了程式列表中的一個位置而已。
假設僅有幾個殭屍程式不會影響系統的執行,可是假設殭屍程式過多。則將會嚴重影響系統的執行。因此,在程式設計過程中應避免產生殭屍程式。有兩種主要的處理方法能夠避免產生殭屍程式:一是父程式忽略SIGCLD訊號;二是父程式捕獲SIGCLD訊號,在訊號處理函式中獲取子程式的退出狀態。忽略訊號的方式比較簡單。僅僅須要呼叫signal(SIGCLD,SIG_IGN)語句就可以完畢。假設要捕獲訊號並處理。那麼先要安裝SIGCLD訊號,然後在訊號處理函式中呼叫wait或者waitpid等函式獲取子程式的退出狀態。
例8-11:程式設計捕獲SIGCLD訊號。輸出各子程式的ID和退出狀態碼。
程式碼例如以下:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
//SIGCLD訊號處理函式
void CbSigCld(int signo)
{
//儲存退出程式的ID
int pid;
//儲存退出程式的退出狀態碼
int status;
//等待不論什麼一個子程式退出
pid=waitpid(-1,&status,0);
//輸出退出的子程式ID和退出程式碼
printf("Child process %d exit with status %d\n",pid,status);
}
void main()
{
int i,pid;
//安裝SIGCLD訊號
if(signal(SIGCLD,CbSigCld)==SIG_ERR)
{
perror("signal");
return;
}
//迴圈建立子程式
for(i=0;i<5;i++)
{
pid=fork();
//假設是子程式
if(pid==0)
{
//退出子程式,退出狀態碼為0
exit(0);
}
//假設是父程式
else
{
sleep(1);
}
}
}