Linux下的signal信号机制
在Linux中,要發送一個信號相當容易。程序員需要知道兩個信息:要發送哪個信號,將這個信號發送給哪個進程??梢杂?man 7 signal 找到一個可以利用的信號的列表。用戶可以只將信號發送給用戶自己的進程,也可以以root身份運行從而將信號發送給任意一進程。
?
Source:
#include<stdio.h> #include<signal.h> #include<unistd.h> #include<stdlib.h> void when_alarm(); void when_sigint(); void when_sigchld(int); void when_sigusr1(); void when_sigio(); int main() { int childpid;//子程序進程ID號 printf("程序已經開始運行,5秒鐘后將接收到時鐘信號。/n"); if ((childpid=fork())>0)//父進程 { signal(SIGALRM,when_alarm); //當接收到SIGALRM信號時,調用when_alarm函數 signal(SIGINT,when_sigint); //當接收到SIGINT信號時,調用when_sigint函數 signal(SIGCHLD,when_sigchld);//當接收到SIGCHLD信號時,調用when_sigchld函數 signal(SIGUSR1,when_sigusr1);//當接收到SIGUSR1信號時,調用when_sigusr1函數 signal(SIGIO,when_sigio);//當接收到SIGIO信號時,調用when_sigio函數 alarm(5); //5秒鐘之后產生SIGALRM信號 raise(SIGIO); //向自己發送一個SIGIO信號 pause(); //將父進程暫停下來,等待SIGALRM信號到來 pause(); //將父進程暫停下來,等待SIGUSR1信號到來 pause(); //將父進程暫停下來,等待SIGCHLD信號到來 printf("------此時程序會停下來等待,請按下ctrl+c送出SIGINT信號-------/n"); pause(); //將父進程暫停下來,等待SIGINT信號到來 } else if(childpid==0) //子進程 { int timer; for(timer=7;timer>=0;timer--) //時鐘計時5秒產生SIGALRM信號,再過2秒子進程退出,產生SIGCHLD信號 { if(timer>2) printf("距離SIGALRM信號到來還有%d秒。/n",timer-2); if(timer==4) kill(getppid(),SIGUSR1); //向父進程發送一個SIGUSR1信號 if((timer<=2)&&(timer>0)) printf("子進程還剩%d秒退出,屆時會產生SIGCHLD信號。/n",timer); if(timer==0) //子進程退出,產生SIGCHLD信號 raise(SIGKILL); //子進程給自己發一個結束信號 sleep(1); //每個循環延時1秒鐘 } } else printf("fork()函數調用出現錯誤!/n"); return 0; } void when_alarm() { printf("5秒鐘時間已到,系統接收到了SIGALRM信號!/n"); } void when_sigint() { printf("已經接收到了SIGINT信號,程序將退出!/n"); exit(0); } void when_sigchld(int SIGCHLD_num) { printf("收到SIGCHLD信號,表明我的子進程已經中止,SIGCHLD信號的數值是:%d。/n",SIGCHLD_num); } void when_sigusr1() { printf("系統接收到了用戶自定義信號SIGUSR1。/n"); } void when_sigio() { printf("系統接收到了SIGIO信號。/n"); } ?
?
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");?
}
總結
以上是生活随笔為你收集整理的Linux下的signal信号机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 缺少using namespace st
- 下一篇: linux dhcp 服务(转)