运行结果如下:

文章插图
代码示例:旧的信号处理函数
sa_flags标志为0代表使用的是旧的信号处理函数
#include <stdio.h>#include <unistd.h>#include <signal.h>void handler(int signo){printf("catch a signal: %d\n", signo);}int main(){int ret = -1;struct sigaction act;//标志为0,代表使用的是旧的信号处理函数指针act.sa_flags = 0;//给阻塞集初始化sigfillset(&act.sa_mask);act.sa_handler = handler;// 信号注册ret =sigaction(SIGINT, &act, NULL);if(ret == -1){perror("sigaction");return 1;}printf("按下任意键退出.....\n");getchar();return 0;}
运行结果如下:
文章插图
代码示例:新的信号处理函数
#include <stdio.h>#include <unistd.h>#include <signal.h>void handler(int signo,siginfo_t *info,void *context){printf("catch a signal: %d\n", signo);}int main(){int ret = -1;struct sigaction act;//使用新的信号处理函数指针act.sa_flags = 0;//给阻塞集初始化sigfillset(&act.sa_mask);act.sa_handler = handler;// 信号注册ret =sigaction(SIGINT, &act, NULL);if(ret == -1){perror("sigaction");return 1;}printf("按下任意键退出.....\n");getchar();return 0; }

文章插图
不可重入函数和可重入函数先看下面一段代码:
#include <stdio.h>#include <signal.h>int a = 10;void SelfAdd(int n){ a = a + n; a = a + n;}void handler(int signo){ SelfAdd(signo);}int main(){ signal(2, handler); SlefAdd(2); printf("%d\n", a); return 0;}
上面我写了一个比较简单的代码,我们慢慢分析,当我们在主函数中执行调用SelfAdd时 , 进入该函数,执行完函数中int a = a + n这句代码后,a变成了12 , 此时收到2号信号,发生中断
文章插图
最后打印a结果是16,其实正常调用该函数的话,打印的应该是18 。像上面这样的因为重入导致结果错乱的函数就叫做不可重入函数 。其中a是一个全局变量 。如果一个函数值访问自己的局部变量或参数,那么这样的函数就叫做可重入函数 。
说的通俗点,不可重入的意思是,如果你定义了一个全局变量,在函数1里面这个变量应该是10,但是有一个函数2改变了这个变量的值,此时本来函数1用的是10 , 你把他改变了,这就是不安全的,这就是不可重入函数 。
思考一个问题:为什么两个不同的控制流程调用同一个函数,访问同一个局部变量或参数不会造成错乱?
在多线程中,每个线程虽然是资源共享,但是他们的栈却是独有的,所以说局部变量不会造成错乱 。
如果一个函数符合以下条件之一则是不可重入的:
- 调用了malloc或free,因为malloc也是用全局链表来管理堆的 。
- 调用了标准I/O库函数 。标准I/O库的很多实现都以不可重入的方式使用全局数据结构 。
- 函数体内使用了静态的数据结构 。
- 在写函数的时候尽量使用局部变量 。(例如寄存器和栈中的变量)
- 对于要使用的全局变量要加以保护(采取中断、信号量互斥的方法),这样构成的函数就一定是可重入函数 。
产生条件:1)子进程终止时
?2)子进程接收到SIGSTOP信号停止的时候
?3)子进程处于停止态,接收到SIGCONT后唤醒时
如何避免僵尸进程:
1)最简单的方法 , 父进程通过wait和waitpid等待子进程函数结束,但是,这会导致父进程挂起 。
2)如果父进程要处理的事情很多,不能挂起,通过signal()函数人为处理信号SIGCHLD , 只有在子进程退出自动调用制定好的回调函数,因为子进程结束后,父进程会收到信号SIGCHLD,可以在回调函数里面用wait或waitpid回收资源 。
#include <stdio.h>#include <unistd.h>#include <signal.h>#include<sys/types.h>#include<sys/wait.h>void sig_child(int signo){ pid_t pid; //处理僵尸进程,-1代表等待任意一个子进程,WNOHANG代表不阻塞 while((pid=waitpid(-1,NULL,WNOHANG))>0) {printf("孩子进程被杀死 %d\n",pid); }}int main(){pid_t pid;//创建捕捉子进程退出信号//只要子进程退出,触发SIGSIGCHLD,自动调用sig_child()signal(SIGCHLD,sig_child());//创建进程pid = fork();if(pid<0){perror("fork");exit(1);}else if(pid == 0){//子进程printf("我是子进程,pid id :%d.我正在退出\n",getpid());exit(0);}else if(pid>0){//父进程sleep(2);//保证子进程先运行printf("我是父亲,我正在退出\n");system("ps -ef|grep defunct");//查看有没有僵尸进程}return 0;}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- too同义词|too的同义词
- 二 SpringCloud - Eureka注册中心,feign远程调用,hystrix降级和熔断
- 焊工证个人信息查询入口 查询入口
- Docker在windows系统以及Linux系统的安装
- 二 京东云开发者| Redis数据结构-List、Hash、Set及Sorted Set的结构实现
- 一篇文章带你了解服务器操作系统——Linux简单入门
- 二、python基本数据类型
- 二 【SSM】学习笔记——SpringMVC入门
- 原神片剂深研第二关怎么通关
- 一步一图带你深入理解 Linux 虚拟内存管理