1. alarm函數
(1) alarm函數原型
alarm(設置信號傳送鬧鐘) | |
所需頭文件 | #include <unistd.h> #include <signal.h> |
函數說明 | alarm()用來設置信號SIGALRM在經過參數seconds指定的秒數後傳送給目前的進程。如果參數seconds 爲0,則之前設置的鬧鐘會被取消,並將剩下的時間返回 |
函數原型 | unsigned int alarm(unsigned int seconds) |
函數返回值 | 返回之前鬧鐘的剩餘秒數,如果之前未設鬧鐘,則返回0 |
(2) alarm函數說明
當所設置的時間值超過後,產生SIGALRM信號。如果不忽略或不捕捉此信號,則其默認動作是終止該進程。
每個進程只能有一個鬧鐘時間。如果在調用alarm時,以前已爲該進程設置過鬧鐘時間,而且它還沒有超時,則該鬧鐘時間的剩餘時間值作爲本次alarm函數調用的值返回,以前登記的鬧鐘時間則被新值代換。
如果有以前登記的尚未超過的鬧鐘時間,而新設的鬧鐘時間值爲0,則取消以前的鬧鐘時間,其剩餘時間值仍作爲函數的返回值。
(3) alarm函數舉例
alarm.c 源代碼如下:
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
void handler() { /*信號處理函數*/
printf("hello\n");
}
int main()
{
int i;
int time ;
signal(SIGALRM,handler); /*註冊SIGALRM信號處理方式*/
alarm(3);
for(i=1;i<5;i++){
printf("sleep %d ...\n", i);
sleep(1);
}
alarm(3);
sleep(2);
time=alarm(0) ; /*取消SIGALRM信號,返回剩餘秒數*/
printf("time=%d\n",time) ;
for(i=1;i<3;i++){
printf("sleep %d ...\n", i);
sleep(1);
}
return 0 ;
}
編譯 gcc alarm.c –o alarm。
執行./alarm,執行結果如下:
sleep 1 ...
sleep 2 ...
sleep 3 ...
hello
sleep 4 ...
time=1
sleep 1 ...
sleep 2 ...
對程序結果分析如下:
信號是一種軟中斷,中斷的原理是保留執行現場,跳轉到中斷函數處執行,執行完後恢復以前的現場在斷點處繼續往下執行。所以alarm函數經過3秒時,for循環已經到了sleep的3秒位置;alarm發送鬧鈴信號,引起中斷,程序執行SIGALRM註冊函數handler(中斷處理函數),即輸出hello。信號處理handler函數執行完後,應用程序從中斷點恢復,繼續執行for循環,此時sleep到了4秒的位置。
alarm(0)取消註冊的鬧鈴(SIGALRM)信號,所以,第二次沒有執行SIGALRM信號註冊函數。
2. kill函數
(1) kill函數原型
kill函數是將信號發送給指定的pid進程。普通用戶利用kill函數將信號發送給該用戶下任意一個進程,而特權用戶(root)可以將信號發送系統中的任意一個進程。
kill函數原型及說明如下:
kill(傳送信號給指定的進程) | ||
所需頭文件 | #include <sys/types.h> #include <signal.h> | |
函數說明 | kill()可以用來傳送參數sig指定的信號給參數pid指定的進程 | |
函數原型 | int kill(pid_t pid,int sig) | |
函數傳入值 | pid | pid>0 將信號傳給進程識別碼爲pid 的進程 |
pid=0 將信號傳給和目前進程相同進程組的所有進程 | ||
pid=-1 將信號廣播傳送給系統內所有的進程 | ||
pid<0將信號傳給進程組識別碼爲pid絕對值的所有進程 | ||
sig | 信號編號 | |
函數返回值 | 成功:0 | |
出錯:-1,錯誤原因存於error中 | ||
錯誤代碼 | EINVAL:參數sig不合法 ESRCH:參數pid 所指定的進程或進程組不存在 EPERM:權限不夠無法傳送信號給指定進程 |
(2) kill函數舉例
下面代碼實現的是父進程發信號給子進程。
kill.c 源代碼如下:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
int status;
pid= fork() ;
if( 0==pid ){
printf("Hi I am child process!\n");
sleep(10);
}
else if ( pid > 0 ){
printf("send signal to child process (%d) \n",pid);
sleep(1);
/*發送SIGABRT信號給子進程,此信號引起接收進程異常終止*/
kill(pid ,SIGABRT);
/*等待子進程返回終止信息*/
wait(&status);
if(WIFSIGNALED(status))
printf("chile process receive signal %d\n",WTERMSIG(status));
}else{
perror("fork error") ;
return -1 ;
}
return 0 ;
}
編譯 gcc kill.c –o kill。
執行./kill,執行結果如下:
Hi I am child process!
send signal to child process (10498)
chile process receive signal 6
3. raise函數
與kill函數不同的是,raise函數運行是向進程自身發送信號。
raise(向自己發送信號) | |
所需頭文件 | #include <sys/types.h> #include <signal.h> |
函數說明 | 向自己發送信號 |
函數原型 | int raise(int sig) |
函數傳入值 | sig:信號 |
函數返回值 | 成功:0 |
出錯:-1,錯誤原因存於error中 |
4. pause函數
(1) pause函數原型
pause(讓進程暫停直到信號出現) | |
所需頭文件 | #include <unistd.h> |
函數說明 | 令目前的進程暫停(進入睡眠狀態),直到被信號(signal)所中斷 |
函數原型 | int pause(void) |
函數返回值 | 只返回-1,錯誤原因存於error中 |
錯誤代碼 | EINTR:有信號到達中斷了此函數 |
(2) pause函數舉例
下面pause.c源代碼簡單的實現了sleep函數的功能。由於SIGALRM信號默認的系統動作爲終止進程,所以在程序調用pause之後就暫停,當3秒後接收到alarm信號時進程就終止。
pause.c源代碼如下:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
int ret ;
ret=alarm(3) ; /*調用alarm定時器函數*/
pause() ;
printf("I have been waken up.\n") ;
return 0 ;
}
編譯 gcc pause.c –o pause。
執行./pause,執行結果如下:
Alarm clock
5. sleep和abort
(1) sleep函數原型
sleep(讓進程暫停執行一段時間) | |
所需頭文件 | #include <unistd.h> |
函數說明 | sleep()會令目前的進程暫停,直到達到參數seconds所指定的時間,或是被信號所中斷 |
函數原型 | unsigned int sleep(unsigned int seconds) |
函數傳入值 | seconds:睡眠的秒數 |
函數返回值 | 若進程暫停到參數seconds所指定的時間,則返回0;若有信號中斷則返回剩餘秒數 |
(2) abort函數原型
abort(以異常方式結束進程) | |
所需頭文件 | #include <stdlib.h> |
函數說明 | 此函數將SIGABRT信號給調用進程,此信號將引起調用進程的異常終止。此時所有已打開的文件流會自動關閉,所有的緩衝區數據會自動寫回。 |
函數原型 | void abort(void) |
(3) sleep、abort函數舉例
sys_sleep.c源代碼如下:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
system("pwd") ;
sleep(9) ; /*wait 9 second*/
printf("Calling abort()\n");
abort();
printf("abort() after\n") ;
return 0; /* This is never reached */
}
編譯 gcc sys_sleep.c -o sys_sleep。
執行./sys_sleep,執行結果如下:
/home/zjkf/public/signal
Calling abort
6. 信號的發送與捕捉簡要總結
對上述信號的發生與捕捉函數簡要總結說明如下:
kill函數可以向有用戶權限的任何進程發送信號,通常用kill函數來結束進程。
與kill函數不同的是,raise函數只向進程自身發送信號。
使用alarm函數可以設置一個時間值(鬧鈴時間),在將來的某個時刻該時間值超過時發送信號。
pause函數使調用進程掛起直至捕捉到一個信號。
摘錄自《深入淺出Linux工具與編程》