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