在Linux中,要發送一個訊號相當容易。程式員需要知道兩個資訊:要發送哪個訊號,將這個訊號發送給哪個進程。可以用 man 7 signal 找到一個可以利用的訊號的列表。使用者可以只將訊號發送給使用者自己的進程,也可以以root身份運行從而將訊號發送給任意一進程。
Source:
#include<stdio.h><br />#include<signal.h><br />#include<unistd.h><br />#include<stdlib.h><br />void when_alarm();<br />void when_sigint();<br />void when_sigchld(int);<br />void when_sigusr1();<br />void when_sigio();<br />int main()<br />{<br /> int childpid;//子程式進程ID號<br /> printf("程式已經開始運行,5秒鐘後將接收到時鐘訊號。/n");<br /> if ((childpid=fork())>0)//父進程<br /> {<br /> signal(SIGALRM,when_alarm); //當接收到SIGALRM訊號時,調用when_alarm函數<br /> signal(SIGINT,when_sigint); //當接收到SIGINT訊號時,調用when_sigint函數<br /> signal(SIGCHLD,when_sigchld);//當接收到SIGCHLD訊號時,調用when_sigchld函數<br /> signal(SIGUSR1,when_sigusr1);//當接收到SIGUSR1訊號時,調用when_sigusr1函數<br /> signal(SIGIO,when_sigio);//當接收到SIGIO訊號時,調用when_sigio函數<br /> alarm(5); //5秒鐘之後產生SIGALRM訊號<br /> raise(SIGIO); //向自己發送一個SIGIO訊號<br /> pause(); //將父進程暫停下來,等待SIGALRM訊號到來<br /> pause(); //將父進程暫停下來,等待SIGUSR1訊號到來<br /> pause(); //將父進程暫停下來,等待SIGCHLD訊號到來<br /> printf("------此時程式會停下來等待,請按下ctrl+c送出SIGINT訊號-------/n");<br /> pause(); //將父進程暫停下來,等待SIGINT訊號到來<br /> }<br /> else if(childpid==0) //子進程<br /> {<br /> int timer;<br /> for(timer=7;timer>=0;timer--) //時鐘計時5秒產生SIGALRM訊號,再過2秒子進程退出,產生SIGCHLD訊號<br /> {<br /> if(timer>2)<br /> printf("距離SIGALRM訊號到來還有%d秒。/n",timer-2);<br /> if(timer==4)<br /> kill(getppid(),SIGUSR1); //向父進程發送一個SIGUSR1訊號<br /> if((timer<=2)&&(timer>0))<br /> printf("子進程還剩%d秒退出,屆時會產生SIGCHLD訊號。/n",timer);<br /> if(timer==0) //子進程退出,產生SIGCHLD訊號<br /> raise(SIGKILL); //子進程給自己發一個結束訊號<br /> sleep(1); //每個迴圈延時1秒鐘<br /> }<br /> }<br /> else<br /> printf("fork()函數調用出現錯誤!/n");<br /> return 0;<br />}<br />void when_alarm()<br />{<br /> printf("5秒鐘時間已到,系統接收到了SIGALRM訊號!/n");<br />}<br />void when_sigint()<br />{<br /> printf("已經接收到了SIGINT訊號,程式將退出!/n");<br /> exit(0);<br />}<br />void when_sigchld(int SIGCHLD_num)<br />{<br /> printf("收到SIGCHLD訊號,表明我的子進程已經中止,SIGCHLD訊號的數值是:%d。/n",SIGCHLD_num);<br />}<br />void when_sigusr1()<br />{<br /> printf("系統接收到了使用者自訂訊號SIGUSR1。/n");<br />}<br />void when_sigio()<br />{<br /> printf("系統接收到了SIGIO訊號。/n");<br />}<br />
Result:
[work@db-testing-com06-vm3.db01.baidu.com c++]$ ./signal_test
程式已經開始運行,5秒鐘後將接收到時鐘訊號。
距離SIGALRM訊號到來還有5秒。
系統接收到了SIGIO訊號。
距離SIGALRM訊號到來還有4秒。
距離SIGALRM訊號到來還有3秒。
距離SIGALRM訊號到來還有2秒。
系統接收到了使用者自訂訊號SIGUSR1。
距離SIGALRM訊號到來還有1秒。
5秒鐘時間已到,系統接收到了SIGALRM訊號!
子進程還剩2秒退出,屆時會產生SIGCHLD訊號。
子進程還剩1秒退出,屆時會產生SIGCHLD訊號。
收到SIGCHLD訊號,表明我的子進程已經中止,SIGCHLD訊號的數值是:17。
------此時程式會停下來等待,請按下ctrl+c送出SIGINT訊號-------
已經接收到了SIGINT訊號,程式將退出!
訊號參考對照表:
Signal |
Description |
SIGABRT |
由調用abort函數產生,進程非正常退出 |
SIGALRM |
用alarm函數設定的timer逾時或setitimer函數設定的interval timer逾時 |
SIGBUS |
某種特定的硬體異常,通常由記憶體訪問引起 |
SIGCANCEL |
由Solaris Thread Library內部使用,通常不會使用 |
SIGCHLD |
進程Terminate或Stop的時候,SIGCHLD會發送給它的父進程。預設情況下該Signal會被忽略 |
SIGCONT |
當被stop的進程恢複啟動並執行時候,自動發送 |
SIGEMT |
和實現相關的硬體異常 |
SIGFPE |
數學相關的異常,如被0除,浮點溢出,等等 |
SIGFREEZE |
Solaris專用,Hiberate或者Suspended時候發送 |
SIGHUP |
發送給具有Terminal的Controlling Process,當terminal被disconnect時候發送 |
SIGILL |
非法指令異常 |
SIGINFO |
BSD signal。由Status Key產生,通常是CTRL+T。發送給所有Foreground Group的進程 |
SIGINT |
由Interrupt Key產生,通常是CTRL+C或者DELETE。發送給所有ForeGround Group的進程 |
SIGIO |
非同步IO事件 |
SIGIOT |
實現相關的硬體異常,一般對應SIGABRT |
SIGKILL |
無法處理和忽略。中止某個進程 |
SIGLWP |
由Solaris Thread Libray內部使用 |
SIGPIPE |
在reader中止之後寫Pipe的時候發送 |
SIGPOLL |
當某個事件發送給Pollable Device的時候發送 |
SIGPROF |
Setitimer指定的Profiling Interval Timer所產生 |
SIGPWR |
和系統相關。和UPS相關。 |
SIGQUIT |
輸入Quit Key的時候(CTRL+/)發送給所有Foreground Group的進程 |
SIGSEGV |
非法記憶體訪問 |
SIGSTKFLT |
Linux專用,數學副處理器的棧異常 |
SIGSTOP |
中止進程。無法處理和忽略。 |
SIGSYS |
非法系統調用 |
SIGTERM |
請求中止進程,kill命令預設發送 |
SIGTHAW |
Solaris專用,從Suspend恢複時候發送 |
SIGTRAP |
實現相關的硬體異常。一般是調試異常 |
SIGTSTP |
Suspend Key,一般是Ctrl+Z。發送給所有Foreground Group的進程 |
SIGTTIN |
當Background Group的進程嘗試讀取Terminal的時候發送 |
SIGTTOU |
當Background Group的進程嘗試寫Terminal的時候發送 |
SIGURG |
當out-of-band data接收的時候可能發送 |
SIGUSR1 |
使用者自訂signal 1 |
SIGUSR2 |
使用者自訂signal 2 |
SIGVTALRM |
setitimer函數設定的Virtual Interval Timer逾時的時候 |
SIGWAITING |
Solaris Thread Library內部實現專用 |
SIGWINCH |
當Terminal的視窗大小改變的時候,發送給Foreground Group的所有進程 |
SIGXCPU |
當CPU時間限制逾時的時候 |
SIGXFSZ |
進程超過檔案大小限制 |
SIGXRES |
Solaris專用,進程超過資源限制的時候發送 |
==========================================================================
signal學習推薦:
訊號(signal)介紹(Linux中國)
http://www.linux-cn.com/html/linux/system/20070505/27605.shtml
Linux 訊號signal處理函數(CSDN)
http://blog.csdn.net/Sunboy_2050/archive/2010/10/16/5945535.aspx
Linux 訊號signal處理機制(CSDN)
http://blog.csdn.net/Sunboy_2050/archive/2010/10/16/5945380.aspx
==========================================================================
程式員可以調用 int raise(int signo) 將一個訊號發送給它自己。這個函數只帶有一個參數,既要發送訊號的編號。如:raise(SIGINT); raise(SIGKILL);
讓人感興趣的是函數 unsigned int alarm(unsigned int seconds) 它可以讓使用者進程在將來某個指定的時間接收到一個訊號。alarm()的唯一參數是將來訊號SIGALRM應該在多少秒以後發送給使用者進程。當使用者調用alarm()時,前面任何一個請求的警示訊號(不包括懸掛起來被阻塞的SIGALRM訊號)都將被取消,調用的傳回值是前面請求的剩餘時間。alarm()範例如下:
if(signal(SIGALRM,alarmhandler)==SIG_ERR)
{
printf("Couldn't register signal handler./n");
}
alarm(5); // 5秒鐘以後,程式將會收到一個SIGALRM訊號
for(i=0;i<10;i++)
{
sleep(3);
}
void alarmhandler(int signum)
{
printf("alarmhandler./n");
}
也可以使用 int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue) 來實現更精確更方便的定時控制。
參數which一般取ITIMER_REAL,它使得使用者的計時器根據系統時鐘來計算時間。當計數時間到期時,它將發送一個SIGALRM訊號。其功能和alarm()一樣,所以使用者不能將兩者同時使用。
結構itimerval的定義如下:
struct itimerval
{
struct timeval it_interval; // 每一次觸發警示後應該被複位的值,為0警示被禁止
struct timeval it_value; // 下一次觸發警示的時間,為0警示將只觸發一次
};
結構timeval的定義如下:
strut timeval
{
long tv_sec; // 秒數
long tv_usec; // 微秒數
};
setitimer()範例如下:
struct itimerval itimer;
itimer.it_interval.tv_usec = 0; // it_interval欄位指定了每一次觸發後應該被複位的值
itimer.it_interval.tv_sec = 2;
itimer.it_value.tv_usec = 0; // it_value欄位指定了直到下一次觸發的時間
itimer.it_value.tv_sec = 5;
setitimer(ITIMER_REAL,&itimer,NULL);
for(i=0;i<10;i++)
{
sleep(3);
}
void alarmhandler(int signum)
{
printf("alarmhandler./n");
}