捕捉信号
一、内核实现信号的捕捉
操作系统会在适当的时候给进程发送信号,但是什么时候是最适当的呢?在上图中,在内核态到用户态的时候会对信号进行处理,同时进行检测,如果这时候发现异常,操作系统就会发送信号。
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