Linux C: 信号及异常和捕捉函数原理
| #define SIGHUP 1 | 終端掛起或控制進程終止 |
| #define SIGINT 2 | 終端中斷(Ctrl+C 組合鍵) |
| #define SIGQUIT 3 | 終端退出(Ctrl+\組合鍵) |
| #define SIGILL 4 | 非法指令 |
| #define SIGTRAP 5 | debug 使用,有斷點指令產生 |
| #define SIGABRT 6 | 由 abort(3)發出的退出指令 |
| #define SIGIOT 6 | IOT 指令 |
| #define SIGBUS 7 | 總線錯誤 |
| #define SIGFPE 8 | 浮點運算錯誤 |
| #define SIGKILL 9 | 殺死、終止進程 |
| #define SIGUSR1 10 | 用戶自定義信號 1 |
| #define SIGSEGV 11 | 段錯誤(無效的內存段) |
| #define SIGUSR2 12 | 用戶自定義信號 2 |
| #define SIGPIPE 13 | 向非讀管道寫入數據 |
| #define SIGALRM 14 | 鬧鐘 |
| #define SIGTERM 15 | 軟件終止 |
| #define SIGSTKFLT 16 | 棧異常 |
| #define SIGCHLD 17 | 子進程結束 |
| #define SIGCONT 18 | 進程繼續 |
| #define SIGSTOP 19 | 停止進程的執行,只是暫停 |
| #define SIGTSTP 20 | 停止進程的運行(Ctrl+Z 組合鍵) |
| #define SIGTTIN 21 | 后臺進程需要從終端讀取數據 |
| #define SIGTTOU 22 | 后臺進程需要向終端寫數據 |
| #define SIGURG 23 | 有"緊急"數據 |
| #define SIGXCPU 24 | 超過 CPU 資源限制 |
| #define SIGXFSZ 25 | 文件大小超額 |
| #define SIGVTALRM 26 | 虛擬時鐘信號 |
| #define SIGPROF 27 | 時鐘信號描述 |
| #define SIGWINCH 28 | 窗口大小改變 |
| #define SIGIO 29 | 可以進行輸入/輸出操作 |
| #define SIGPOLL | SIGIO |
| #define SIGPWR 30 | 斷點重啟 |
| #define SIGSYS 31 | 非法的系統調用 |
| #define SIGUNUSED 32 | 未使用信號 |
轉載:「一只青木呀」的原創文章,原文鏈接:https://blog.csdn.net/weixin_45309916/article/details/111939072
一、信號和中斷
?
? ? ? ?信號是進程間通信的重要內容之一。它可以來源于硬件,例如鍵盤的 Ctrl+C 組合鍵,間隔定時器,IO錯誤等硬件錯誤;也可以是來源于自己,例如自己的代碼除0,指針越界等執行報錯;其中最需要了解的是來自于其他進程例如 kill命令。信號可以被捕捉從而觸發信號處理函數。信號處理函數可以被重寫,信號也可以被屏蔽。
? ? ? ? 在進程結構體PROC 中,都有一個信號處理數組 int sig[32] ; 其中值為0 代表默認處理,1代表忽略,其他非零值表示用戶模式下預先設定好的信號處理函數地址。除了信號處理數組每個PROC都有一個32位向量(信號位向量) 和Mask(屏蔽)位向量? 。 bits向量用來指明哪些信號被signal? , masks 用來指明哪些信號被Block 。當信號位為1時,且屏蔽位為0時,信號才會生效并傳遞給進程。如果進程發現了個未被阻塞的信號,則會將信號位清0。
二、信號的捕捉和捕捉函數的設置?
? ? ? ? 信號處理內容可以被修改,除了 SIGKILL(9)? 和 SIGSTOP(19)? 。 為了處理信號捕捉可能造成的死循環,這兩個信號9和19作為終止進程的最后手段,規定了不能被修改。
? ? ? ?進程可以使用系統調用來修改捕捉到信號時的信號處理函數:
? ? ? int r = signal (int signal_number , void *handler) ;?
? ? ?但是signal 函數有幾個個缺點:
? ? 1。如果信號觸發頻率過快,可能導致下一個信號和信號處理函數重新設置會出現競態條件。相同的,signal是線程不安全的,可能不適用于多線程。
? ? 2.? signal不能阻塞其他信號,只能通過sigprocmask()來顯示屏蔽或者接觸屏蔽信號
? ? 3.signal 只能傳輸一個信號編號,不能夠傳輸關于信號的其他信息?
因此,現在大多數都用sigaction()? 來代替 signal:
sigaction()? 的系統調用和 sigaction 結構體如下:
int sigaction(int sigid ,const struct sigaction *act , struct sigaction *oldact );struct sigaction{ void (*sa_handler)(int); void (*sa_sigaction)(int , siginfo_t *,void *); sigset_t sa_mask; int sa_flags; void (*sa_restorer)(int); }sa_handler : 指向處理函數的指針
sa_sigaction :另一種方法,指向處理函數的指針 , 外加上了兩個額外的參數。其中siginfo_t 接收信號的更多信息。
sa_mask? ?: 在處理函數執行時,設置要阻塞的信號
sa_flags ;? ? 設置信號處理過程的行為,如果用sa_sigaction處理函數,sa_flags 需設置為 SA_SIGINFO.
sigaction:的示例:
#include <stdio.h> #include <unistd.h> #include <signal.h> #include <string.h> void handler (int sig ,siginfo_t *siginfo , void * context){printf("handler:sig = %d from PID=%d UID=%d \n",sig,siginfo->si_pid,siginfo->si_uid); }int main(int argc, char * argv[]){struct sigaction act ;memset(&act ,0 ,sizeof(act));act.sa_sigaction = &handler ;act.sa_flags =SA_SIGINFO ;sigaction(SIGTERM,&act ,NULL);printf("looping\n");printf("enter kill PID=%d to send SIGTERM signal to it \n" , getpid());while(1){sleep(10);} }上面的代碼利用sigaction 重新設置SIGTERM (15) 信號,當收到 15信號時就會執行 handler內容。開啟另一個會話對進程發出kill命令,則會有上面的輸出結果。最后發出的8信號對應是浮點異常信號,雖然上述程序并不會出現浮點異常,但是由于程序收到了該信號,就執行默認的信號8處理函數了.
三、利用sigaction和管道實現消息IPC
Linux 管道和和文件描述符的相關內容:可看
https://blog.csdn.net/superSmart_Dong/article/details/118641774
/****sigaction*****/ #include <stdio.h> #include <fcntl.h> #include <string.h> #include <signal.h>#define LEN 64 int ppipe[2]; //管道-文件描述符 int pid ; char line[LEN]; int parent(){printf("parent %d running \n",getpid());close(ppipe[0]); // 關閉標準輸入文件描述符while(1){printf("parent %d : input a line : \n" ,getpid());fgets(line ,LEN,stdin); // line[LEN]得到標準輸入line[strlen(line) -1 ] = 0 ;printf("parent %d write to pipe",getpid());write(ppipe[1],line,LEN); //向管道寫入內容printf("parent %d send signal 10 to %d",getpid(),pid);kill(pid,SIGUSR1);} } void chandler(int sig){printf ("\n child %d got an interrupt sig=%d \n ",getpid(),sig);read(ppipe[0] ,line ,LEN); //向管道讀出內容 printf("child %d get a message = %s \n" ,getpid(),line); } int child(){char msg[LEN];int parent =getppid();printf("child %d running \n",getpid());close(ppipe[1]);signal(SIGUSR1,chandler);while(1); } int main(int argc, char * argv[]){pipe(ppipe);pid = fork();if (pid){parent();}else{child();} }?
?
?
總結
以上是生活随笔為你收集整理的Linux C: 信号及异常和捕捉函数原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux C: 定时器及时钟服务
- 下一篇: Linux C: 文件操作相关的系统调用