首页 > 代码库 > 2信号处理之:信号产生原因,进程处理信号行为,信号集处理函数,PCB的信号集,sigprocmask()和sigpending(),信号捕捉设定,sigaction,C标准库信号处理函数,可重入函数,
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;
}
2信号处理之:信号产生原因,进程处理信号行为,信号集处理函数,PCB的信号集,sigprocmask()和sigpending(),信号捕捉设定,sigaction,C标准库信号处理函数,可重入函数,