歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Linux編程---信號處理

信號是一種異步的進程間通信的方式.但是這種通知方式能交換的信息很少.只能說給一個事件的標志.類似單片機中的中斷,強迫進程停止做當前應當做的事情,而去執行中斷執行程序。
 
信號的產生有如下幾種:
 
1.用戶按下了某個終止鍵,如ctrl-\或ctrl-c.是由終端程序向當前進程發送一個中斷信號.
 
2.程序異常.比如除零錯誤.
 
3.kill函數向其發送了一個終止信號
 
4.進程向自己發送信號.如進程調用alarm函數.
 
5.企圖讀寫終端的後台進程會得到作業的控制信號SIGTTIN或SIGTOU.
 
6.當進程超越了CPU或文件的大小限制時,內核會生成一個信號.
 
Linux的信號處理和實際使用(結合Redis分析)  http://www.linuxidc.com/Linux/2014-03/98787.htm

Linux-信號處理 http://www.linuxidc.com/Linux/2012-06/63883.htm

一步一步學Linux C:信號處理潛在危險!!! http://www.linuxidc.com/Linux/2012-03/57195.htm

一步一步學Linux C:信號處理方法 && 實際應用 http://www.linuxidc.com/Linux/2012-03/57074.htm

Linux信號簡介和信號處理相關函數 http://www.linuxidc.com/Linux/2011-04/34500.htm
 
得到信號的進程也有三種方式應對.
 
1.忽略信號.大部分信號都可以忽略,但SIGSTOP和SIGKILL除外
 
2.捕獲信號.這就要進程對信號進行專門的設置了.
 
3.執行系統默認動作.這個主要是系統默認對信號規定的默認動作.
 
---流產: 終止進程並且生成內存轉儲文件.即產生存儲上下文環境,寄存器內容等信息的core文件.(abort函數)
 
---終止: 這個不產生core文件
 
---忽略: 忽略信號
 
---掛起: 暫停進程
 
---繼續: 恢復進程.
 
 
 
對於進程正處在可中斷的睡眠狀態並且這個信號是非阻塞的,內核便喚醒此進程使它能夠接受信號.
 
對於信號,進程可以立即處理,也可以選擇讓其懸掛.對於不可靠信號,一個進程對同一種信號只能懸掛一個.也就是信號可以存儲,但是只能存一個.對於可靠信號,信號來幾個就執行幾次信號句柄,信號可以排隊,所以可以用來計數.
 
對於小於SIGRTMIN的信號為不可靠信號,SIGRTMIN-SIGRTMAX為可靠信號.實際上實時對應可靠,非實時對應不可靠.
 
 
 
這裡是我抄網上的,測試版本為Ubuntu 12.04LTS.我之前也不太明白實時和非實時,可靠和不可靠信號的差別.如果理解有誤還請指出.
 
 
 
這裡介紹一個NSIG宏.這個宏記錄了系統中允許的信號總數+1.
 
 
 
void psignal(int signo,const char *msg);
 
這個函數我第一次見...網上貌似也沒資料.....
 
若msg是控制正,函數只打印signo對應的描述,並隨後帶上一個換行符.
 
若msg是非空指針,平函數用這個字符串作為其輸出消息的前綴,並且在此前綴和signo對應的消息之間放置一個冒號和空格將他們分開.
 
 
 
簡單來說就是查詢信號用途的函數...
 
 
 
不同信號類型中的信號也蠻多的...具體的還是以後編程遇到後慢慢記吧.這裡就不寫了.
 
 
 
還是寫一些函數的說明吧...
 
 
 
一.信號生成
 
int raise(int sig);
 
這個函數功能就是發送sig到調用進程...
 
如果sig信號設置了句柄,那麼raise只有在句柄函數返回時才會返回.
 
 
 
int kill(pid_t pid,int sig);
 
這個函數用的比較多吧.雖說叫kill,但實際上是發送信號的函數.並不一定只能發送kill.
 
如果sig為0,那麼kill只進行正常的錯誤檢查而不實際發送信號,這常常用來檢查pid的合法性.如果發送信號的進程可能不在的話,那麼就可以這麼用.
 
pid實際上參數用法還蠻多的.
 
>0  發送信號給pid進程
 
=0  發送給進程所在的進程組的所有進程.
 
=-1 廣播信號,即發送給能發送的所有進程.
 
<-1 發送信號給進程組ID等於pid絕對值.並且發送者有權向它發送信號的所有進程.
 
 
 
這個pid的取值和之前的wait很像.
 
 
 
這裡還提到了權限的問題.一般進程的實際用戶ID或有效用戶ID必須與接受信號進程的實際用戶ID或有效用戶ID相同.對於有效ID是超級用戶的進程來說,可以向任何進程發送信號.
 
 
 
 
 
二.設置信號動作.
 
typedef void (*sighandler_t)(int );
 
sighandler_t signal(int signum,sighandler_t handler);
 
兩個參數:signum設置型號類型.handler設置信號句柄.
 
handler其實可以取以下三種值之一:
 
SIG_DFL 默認動作
 
SIG_IGN 忽略該信號.但SIGKILL和SIGSTOP這兩個信號,不能設置為忽略.盡量不要忽略系統相關的信號.
 
函數指針 就是執行這個函數體的函數.參數一般得到的是信號類型.
 
 
 
這個函數的返回值是前一次有效動作的指針.,因此它的原型與第二個參數相同.當signal調用成功時.返回值要麼是SIG_DFL,SIGIGN或函數句柄.
 
 
 
如果調用出錯,那麼則會返回SIG_ERR並設置errno.唯一的錯誤嗎是EINVAL
 
 
 
對於fork和exec來說,信號相關對於fork來說是繼承的.
 
對exec來說則不繼承.所有忽略的信號繼續忽略,其他有句柄的則改為默認動作.
 
 
 
 
 
由於signal函數使用的時候存在一個時間窗口,信號很可能不可靠.所以有了下面這個信號函數.通常用它的比較多
 
int sigaction (int signum,const struct sigaction *act,struct sigaction *oact);
 
第二個參數是一個結構體,其中包含了信號句柄.第三個參數則是原來的信息.
 
struct sigaciton{
 
  void  (*sa_handler)(int);
 
  void  (*sa_sigaction)(int ,siginfo_t *,void *);
 
  sigset_t sa_mask;
 
  int    sa_flags;
 
}
 
sa_handler就是句柄.
 
sa_sigaction也是個句柄地址,當sa_flags設置了SA_SIGINFO的時候才起作用,否則用handler.
 
sa_mask指明信號句柄執行期間要阻塞的一組信號,在sigaction執行過程中會屏蔽這些信號.
 
sa_flags可取的值就多了,有以下這些:
 SA_NOCLDSTOP
 
此標志只對SIGCHLD信號有效,正常情況下,子進程被停止時,總是向父進程發送信號,有時候被停止的子進程恢復運行時,可能向父進程發送信號.當signum參數傳值是SIGCHLD時,在這兩種情況下都不再發送信號.
 
SA_RESTART
 
如果設置該標志並且捕獲信號,系統將在信號句柄返回時自動恢復被該信號中斷了的系統調用.否則被中斷的系統調用將返回-1並置errno為EINTR.多數情況下sa_flags的值為SA_RESTART.
 
SA_ONSTACK
 
如果設置此標志,系統將在用sigaltstack指定的替代信號棧上運行的信號句柄.否則使用用戶棧來交付信號.
 
SA_NODEFER
 
如果設置此標志並且捕獲信號,在信號句柄執行期間系統不自動阻塞該信號.這對應於不可靠信號signal的情形.(估計沒什麼人會用這個吧...)
 
SA_RESETHAND
 
如果設置此標志並且捕獲信號,在信號句柄的入口,系統將重置信號動作為SIG_DFL並清楚SA_SIGINFO標志,並且sigaction的行為就和signal差不多了.
 
SA_NOCLDWAIT
 
只對SIGCHLD起作用.如果設置此標志,並且sig是SIGCHLD,調用進程的所有子進程在終止時不轉變成僵死進程.這樣父進程就不必調用wait函數了.如果調用了wait則進程會一直阻塞直到所有子進程都結束才返回,返回值為-1和設置errno為ECHILD.
 
SA_SIGINFO
 
這個就是上面的情況了.未設置用sa_handler並且禁止修改sa_sigaction.
 
句柄原型必須是void f(int signo);
 
如果設置了這個標志,則必須修改sa_sigaction設置信號句柄並禁止修改sa_handler.
 
句柄原型為void f(int signo,siginfo *info,void *context);
 
這個有些復雜,不過還是可以說清楚的.
 
實際上在siginfo_t中包含了更多的信號產生的信息.context也指向了一個進程上下文環境.Linux下默認類型為sigcontext結構體.
 
這個內容好多...我就不展開了,我看APUE上有相關信息,用到再查吧.

更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2014-06/103489p2.htm

Copyright © Linux教程網 All Rights Reserved