2信号处理之:信号产生原因,进程处理信号行为,信号集处理函数,PCB的信号集,sigprocmask()和sigpending(),信号捕捉设定,sigaction,C标准库信号处理函数,可重入函数,
1信號產生原因
2.進程處理信號行為
manpage里信號3中處理方式:
SIG_IGN
SIG_DFL??????????????????????????????????????????? 默認Term動作
a signal handling function
進程處理信號
A默認處理動作
term?? 中斷
core??? core(調試的時候產生)
gcc –g file.c
?? ?ulimit –c 1024
?? ?gdb a.out core
ign????? 忽略
stop???? 停止
cont???? 繼續
B忽略
C捕捉(用戶自定義處理函數)
3信號集處理函數
sigset_t為信號集,可sizeof(sigset_t)查看
將信號集里面的每位都置0
int sigemptyset(sigset_t *set)
將所有信號集都置1
int sigfillset(sigset_t *set)
添加一個信號,也就是將Block阻塞信號集里面的某一位置成1
int sigaddset(sigset_t *set, int signo)
將信號集中某一位取消置1
int sigdelset(sigset_t *set, int signo)
測試某個信號集中的信號是否為1
int sigismember(const sigset_t *set, intsigno)
4 PCB的信號集
信號在內核中的表示示意圖
如果在進程解除對某信號的阻塞之前這種信號產生過多次,將如何處理?POSIX.1允
許系統遞送該信號一次或多次。Linux是這樣實現的:常規信號在遞達之前產生多次只
計一次,而實時信號在遞達之前產生多次可以依次放在一個隊列里。本章不討論實時信
號。從上圖來看,每個信號只有一個bit的未決標志,非0即1,不記錄該信號產生了多少
次,阻塞標志也是這樣表示的。因此,未決和阻塞標志可以用相同的數據類型sigset_t
來存儲,sigset_t稱為信號集,這個類型可以表示每個信號的“有效”或“無效”狀態,
在阻塞信號集中“有效”和“無效”的含義是該信號是否被阻塞,而在未決信號集中“有
效”和“無效”的含義是該信號是否處于未決狀態。
阻塞信號集也叫做當前進程的信號屏蔽字(Signal Mask),這里的“屏蔽”應該理解
為阻塞而不是忽略。
5sigprocmask
調用函數sigprocmask可以讀取或更改進程的信號屏蔽字。
依賴的頭文件:
#include <signal.h>
函數聲明:
*set是傳入的信號,*oset表示原來的信號集是什么,相當于是*set的一個備份
intsigprocmask(int how, const sigset_t *set, sigset_t *oset);?????????
返回值:若成功則為0,若出錯則為-1
如果oset是非空指針,則讀取進程的當前信號屏蔽字通過oset參數傳出。如果set是非空指針,則更改進程的信號屏蔽字,參數how指示如何更改。如果oset和set都是非空指針,則先將原來的信號屏蔽字備份到oset里,然后根據set和how參數更改信號屏蔽字。假設當前的信號屏蔽字為mask,下表說明了how參數的可選值。
??? how參數的含義
SIG_BLOCK set包含了我們希望添加到當前信號屏蔽字的信號,相當于mask=mask|set
SIG_UNBLOCK set包含了我們希望從當前信號屏蔽字中解除阻塞的信號,相當于mask=mask&~set
SIG_SETMASK 設置當前信號屏蔽字為set所指向的值,相當于mask=set
6sigpending(未決打印信號)
#include<signal.h>
int sigpending(sigset_t *set)
sigpending讀取當前進程的未決信號集,通過set參數傳出。調用成功則返回0,出錯則
返回-1。
6案例說明:
運行結果:
程序運行時,每秒鐘把各信號的未決狀態打印一遍,由于我們阻塞了SIGINT信號,按Ctrl-C將會使SIGINT信號處于未決狀態,按Ctrl-\仍然可以終止程序,因為SIGQUIT信號沒有阻塞。
這時按Ctrl+\結束。
7信號捕捉設定
8.sigaction
#include <signal.h>
int sigaction(int signum, const structsigaction *act,
struct sigaction *oldact);
?
struct sigaction 定義:
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
sa_handler:早期的捕捉函數
sa_sigaction : 新添加的捕捉函數,可以傳參,和sa_handler互斥,兩者通過sa_flags選擇采用哪種捕捉函數
sa_mask : 在執行捕捉函數時,設置阻塞其它信號,sa_mask| 進程阻塞信號集,退出捕捉函數后,還原回原有的阻塞信號集
sa_flags : SA_SIGINFO 或者0
sa_restorer:保留,已過時。
案例說明:
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
?
void do_sig(int num)
{
????int n = 5;
????printf("I am do_sig\n");
????printf("num = %d\n",num);
????while(n--)
????{
?? ??????printf("num = %d\n",num);
????????sleep(1);
????}
}
?
int main(void)
{
????struct sigaction act;
????act.sa_handler = do_sig;
????//act.sa_handler = SIG_DFL;
????//act.sa_handler = SIG_IGN;
????sigemptyset(&act.sa_mask);
????sigaddset(&act.sa_mask,SIGQUIT);
????act.sa_flags = 0;
?
????sigaction(SIGINT,&act,NULL);
?
??? ?while(1)
????{
????????printf("**********\n");
?????? sleep(1);
????}
????return 0;
}
9 C標準庫信號處理函數
typedef void (*sighandler_t)(int)
sighandler_t signal(int signum,sighandler_t handler)
int system(const char *command)
system的本質是:集合fork,exec,wait一體
10 可重入函數
A:不含全局變量和靜態變量是可重入函數的一個要素
B:可重入函數man? 7??signal
C:在信號捕捉函數里應可重入函數
例如:strtok就是一個不可重入函數,因為strtok內部維護了一個內部靜態指針,保存上一次切割到的位置,如果信號的捕捉函數中也去調用strtok函數,則會造成切割字符串混亂,應用strtok_r版本,r表示可重入。
11時序競態
int pause(void)
使調用進程掛起,直到有信號遞達,如果遞達信號是忽略,則繼續掛起
int sigsuspend(const sigset_t *mask)
以通過指定mask來臨時解除對某個信號的屏蔽,然后掛起等待,當sigsuspend返回時,進程的信號屏蔽字恢復為原來的值
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
void sig_alrm(int signo)
{
/* nothing to do */
}
unsigned int mysleep(unsigned int nsecs)
{
struct sigaction newact, oldact;
unsigned int unslept;
newact.sa_handler = sig_alrm;
sigemptyset(&newact.sa_mask);
newact.sa_flags = 0;
sigaction(SIGALRM, &newact, &oldact);
?
alarm(nsecs);
//在alarm的時候,可能會轉到其它程序,這之后永遠都執行不到下面的這行,因為信號已經執行過了
pause();
?
unslept = alarm(0);
sigaction(SIGALRM, &oldact, NULL);
return unslept;
}
?
int main(void)
{
while(1){
mysleep(2);
printf("Two seconds passed\n");
}
return 0;
}
mysleep的改進版
#include<unistd.h>
#include<signal.h>
#include<stdio.h>
?
void sig_alrm(int signo)
{??
????/* nothing to do*/
}
?
unsigned int mysleep(unsigned int nsecs) {??
struct sigaction newact,oldact;
??? sigset_tnewmask,oldmask,suspmask;
??? unsigned int unslept;
??? /*set our handler,saveprevious information*/
??? newact.sa_handler =sig_alrm;
? ??sigemptyset(&newact.sa_mask);
??? newact.sa_flags = 0;
???sigaction(SIGALRM,&newact,&oldact);
??? /*block SIGALRM and savecurrent signal mask*/
??? sigemptyset(&newmask);
?sigaddset(&newmask,SIGALRM);
?sigprocmask(SIG_BLOCK,&newmask,&oldmask);
?? ???alarm(nsecs);
???suspmask = oldmask;
? /*make sure SIGALRM isn'tblocked*/
???sigdelset(&suspmask,SIGALRM);
? sigsuspend(&suspmask);/*waitfor any signal to be caught*/
??? /*some signal has bencaught,SIGALRM is now blocked*/
??unslept = alarm(0);
?? ???sigaction(SIGALRM,&oldact,NULL);/*resetprevious action*/
??? /*reset signal mask,whichunblocks SIGALRM*/
???sigprocmask(SIG_SETMASK,&oldmask,NULL);
???return(unslept);
}
?
int main(void) {
while(1)
??? {
???? ????sleep(2);
?? printf("Two secondspassed\n");
? ????}
? return 0;
}
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的2信号处理之:信号产生原因,进程处理信号行为,信号集处理函数,PCB的信号集,sigprocmask()和sigpending(),信号捕捉设定,sigaction,C标准库信号处理函数,可重入函数,的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 苹果笔记本怎么安装双系统 苹果笔记本安装
- 下一篇: 3信号处理之:避免异步IO的类型,SIG