捕捉信号
一、内核实现信号的捕捉
操作系统会在适当的时候给进程发送信号,但是什么时候是最适当的呢?在上图中,在内核态到用户态的时候会对信号进行处理,同时进行检测,如果这时候发现异常,操作系统就会发送信号。
sighandler和main函数是使用不同的堆栈空间,它们之间不存在调用和被调用的关系,是两个独立的控制流程。
二、sigaction
int sigaction(int signo,const struct sigaction* act,struct sigaction* oact);
struct sigaction {
void (*sa_handler)(int);//信号的处理动作
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;//当正在执行信号处理动作时,希望屏蔽的信号。当处理结束后,自动解除屏蔽
int sa_flags;//一般为0
void (*sa_restorer)(void);
};
sigaction函数可以读取和修改与指定信号相关联的处理动作。成功为0,失败为-1.
signo是指定信号的编号。
若act指针非空,则根据act修改该信号的处理动作。
若oact指针非空,则通过oact传出该信号原来的处理动作。
3.pause
#include<unistd.h>
int pause(void);
pause函数使调用进程挂起知道有信号递达。
若信号的处理动作是终止进程,则pause函数是没有机会返回的。
若信号的处理动作是忽略,则进程继续处于挂起状态,pause不返回。
若信号的处理动作是捕捉,则调用了信号处理函数之后,pause返回-1。
以下用sigaction pause sleep实现一个mysleep程序
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void sig_alrm(int signo)
{
//DO NOTHING
}
unsigned int mysleep(unsigned int nsecs)
{
[root@du mysleep]# ./mysleep
5 seconds passed
5 seconds passed
^C
2号信号为自定义。
void handler(int signo)
{
printf("this signo is: %d\n",signo);
}
int main()
{
signal(2,handler);
int ret = mysleep(5);
printf("ret = %d\n",ret);
return 0;
}
[root@du mysleep]# ./mysleep
^Cthis signo is: 2
ret = 4
可重入函数
若一个函数被不同的控制流程调用,用可能在第一次调用还没有返回的时候就再次进入了该函数,这称为重入,
如果该函数访问一个全局链表,有可能因为重入而造成错乱,这样称为不可重入。
但如果一个函数只访问自己的局部变量或参数,称为可重函数。
注:如果一个函数符合以下条件之一,则不可重入:
1.调用了malloc和free,因为malloc也是用全局链表来管理堆的。
2.调用了标准I/O库函数,I/O库中好多的实现都是以不可重入的方式使用全局数据结构。
volatite:保证内存的可见性,始终从内存中查看。
SIGCHLD
字进程在终止时,会给父进程发SIGCHLD信号,该信号的默认处理动作是忽略,父进程可以自定义SIGCHLD的处理函数,这样父进程只需处理自己的工作,子进程终止时会通知父进程,父进程在信号处理函数中调用wait清理进程即可。
其实要想不产生僵尸进程还有方法:父进程调用sigaction将SIGCHLD的处理方式设置为SIG_ING这样fork出来的子进程在终止时将会自动清理。但此方法只适合用于linux。
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
void handler(int sig)
{
pid_t id;
while((id = waitpid(-1,NULL,WNOHANG))>0)
{
printf("wait child success: %d\n",getpid());
}
}
int main()
{
signal(SIGCHLD,handler);
pid_t cid;
if((cid = fork()) == 0)
{
printf("child : %d\n",getpid());
sleep(3);
exit(1);
}
while(1)
{
printf("father proc is doing some thing!\n");
sleep(1);
}
return 0;
}
################
2676 9054 9054 2676 pts/1 9054 S+ 0 0:00 ./sigchld
9054 9055 9054 2676 pts/1 9054 S+ 0 0:00 ./sigchld
################
2676 9054 9054 2676 pts/1 9054 S+ 0 0:00 ./sigchld
9054 9055 9054 2676 pts/1 9054 S+ 0 0:00 ./sigchld
################
2676 9054 9054 2676 pts/1 9054 S+ 0 0:00 ./sigchld
9054 9055 9054 2676 pts/1 9054 S+ 0 0:00 ./sigchld
################
2676 9054 9054 2676 pts/1 9054 S+ 0 0:00 ./sigchld
################
2676 9054 9054 2676 pts/1 9054 S+ 0 0:00 ./sigchld