当前位置: 首页 > news >正文

【项目 进程12】2.25 sigprocmask函数使用 2.26sigaction信号捕捉函数 2.27SIGCHILD信号

文章目录

    • 2.25 sigprocmask函数使用
    • 2.26 sigaction信号捕捉函数
      • 内核实现信号捕捉的过程
      • 信号捕捉特性
    • 2.27SIGCHILD信号


2.25 sigprocmask函数使用

在这里插入图片描述阻塞信号集有时称作信号掩码。
联想:fcntl函数可以修改fd属性。

./sigprocmask &  //将程序设置为后台运行,输入ls可以同步有输出
fg              //将程序恢复到前台运行
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>int main() {// 设置2、3号信号阻塞sigset_t set;sigemptyset(&set);// 将2号和3号信号添加到信号集中sigaddset(&set, SIGINT);sigaddset(&set, SIGQUIT);// 修改内核中的阻塞信号集sigprocmask(SIG_BLOCK, &set, NULL);int num = 0;while(1) {num++;// 获取当前的未决信号集的数据sigset_t pendingset;sigemptyset(&pendingset);sigpending(&pendingset);// 遍历前32位for(int i = 1; i <= 31; i++) {if(sigismember(&pendingset, i) == 1) {printf("1");//未决}else if(sigismember(&pendingset, i) == 0) {printf("0");//非未决}else {perror("sigismember");exit(0);}}printf("\n");sleep(1);if(num == 10) {// 解除阻塞,SIGINT默认动作是终止进程sigprocmask(SIG_UNBLOCK, &set, NULL);}}return 0;
}

ctrl + C 2号信号:SIGINT
ctrl + \ 3号信号:SIGQUIT
ctrl + Z 19号信号:SIGTSTP

./out & 就是在后台运行
此时再输入ls之类的指令是可以的
fg:调到前台来运行,此时就无法输入其他指令,只能再开一个终端
在这里插入图片描述

2.26 sigaction信号捕捉函数

相较于signal函数,优先使用sigaction信号捕捉函数。(标准的原因)
在这里插入图片描述
在这里插入图片描述

#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>void myalarm(int num) {printf("捕捉到了信号的编号是:%d\n", num);printf("xxxxxxx\n");
}// 过3秒以后,每隔2秒钟定时一次
int main() {struct sigaction act;act.sa_flags = 0;act.sa_handler = myalarm;sigemptyset(&act.sa_mask);  // 清空临时阻塞信号集// 注册信号捕捉sigaction(SIGALRM, &act, NULL);struct itimerval new_value;// 设置间隔的时间new_value.it_interval.tv_sec = 2;new_value.it_interval.tv_usec = 0;// 设置延迟的时间,3秒之后开始第一次定时new_value.it_value.tv_sec = 3;new_value.it_value.tv_usec = 0;int ret = setitimer(ITIMER_REAL, &new_value, NULL); // 非阻塞的printf("定时器开始了...\n");if(ret == -1) {perror("setitimer");exit(0);}// getchar();//等待键盘录入while(1);return 0;
}

显示结果:

内核实现信号捕捉的过程

在这里插入图片描述

信号捕捉特性

1、假设信号捕捉到,信号捕捉代码仍在执行,又发送一个信号,该信号会被执行嘛?
这个信号不会被处理,阻塞在那!
未决信号集中SIGALRM信号为1,若处理myalarm函数,则未决信号集中SIGALRM信号为0,如果一直在处理,又产生一个SIGALRM信号,则它的未决信号标志位变成1,阻塞在那,不会执行回调函数。当上一次的回调函数执行完,第二个信号的回调函数才会被执行,它的未决信号标志位再次变成0。
在myalarm回调函数使用的过程当中,SIGALARM信号自动被屏蔽,不许我们设置,为系统行为,当回调函数执行结束,SIGALARM信号不被屏蔽。
2、执行回调函数时使用临时阻塞信号集,当回调结束使用内核当中的信号集。(可能在执行回调函数的时候不希望被某些信号打断)
3、常规信号阻塞的时候不支持排队。不支持记录有多少个信号被阻塞未决。其他34-64,30个实时信号支持排队。

2.27SIGCHILD信号

在这里插入图片描述使用SIGCHLD信号解决僵尸进程的问题。
子进程结束时父进程有责任回收子进程的资源,一般不断循环调用wait(阻塞)或waitpid函数。实际过程中,父进程需要执行一些其他的操作,不可能一直阻塞等待回收子进程的资源。解决方案:捕捉SIGCHILD信号再调用wait(阻塞)或waitpid函数。
wait或waitpid函数一次只能回收一个子进程的资源。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <sys/wait.h>void myFun(int num) {printf("捕捉到的信号 :%d\n", num);// 回收子进程PCB的资源//不使用while循环时,子进程回收不完全,未决信号集一次只能记录一个状态,产生的其余信号都被舍弃掉//死循环时,父进程一直被阻塞,不推荐// while(1) {//     wait(NULL); /*17号信号进入未决信号集合,17位置1进入回调函数,17位置0但是如果有多个子进程同时结束发送信号未决信号集是不能累计的也就是说它只能处理一个信号那么其他同时发送的信号就被忽略了这种处理方式僵尸进程处理不干净这个地方直接加while是没有意义的,因为一旦程序进入while就会一直阻塞在wait函数。此时进程结束的信号初步处理都没有意义了因为父进程一直卡在这里等待所有子进程结束*/// }while(1) {int ret = waitpid(-1, NULL, WNOHANG);//所以在这里设置非阻塞 只要有信号,就会进来处理已经死亡的进程,而不管是哪一个。if(ret > 0) {printf("child die , pid = %d\n", ret); //继续while} else if(ret == 0) {// 说明还有子进程活着,没就结束这个回调函数,继续等下一个子进程死亡 给出SIGCHLD信号break;} else if(ret == -1) {// 说明没有子进程了,直接break除去break;}}
}int main() {// 提前设置好阻塞信号集,阻塞SIGCHLD,因为有可能子进程很快结束,父进程还没有注册完信号捕捉sigset_t set;sigemptyset(&set);sigaddset(&set, SIGCHLD);sigprocmask(SIG_BLOCK, &set, NULL);// 创建一些子进程20个pid_t pid;for(int i = 0; i < 20; i++) {pid = fork();if(pid == 0) {//阻止孙进程的创建break;}}if(pid > 0) {// 父进程// 捕捉子进程死亡时发送的SIGCHLD信号struct sigaction act;act.sa_flags = 0;act.sa_handler = myFun;sigemptyset(&act.sa_mask);//信号捕捉还没有注册成功,子进程就已经结束?就会产生问题,不能回收子进程//需要提前设置好阻塞信号集,阻塞SIGCHLDsigaction(SIGCHLD, &act, NULL);// 注册完信号捕捉以后,解除阻塞sigprocmask(SIG_UNBLOCK, &set, NULL);while(1) {printf("parent process pid : %d\n", getpid());sleep(2);}} else if( pid == 0) {// 子进程printf("child process pid : %d\n", getpid());}return 0;
}
http://www.lryc.cn/news/107970.html

相关文章:

  • 【无标题】面试题 02.07. 链表相交
  • Zotero ubuntu2023安装 关联 ubuntu文献翻译
  • Stable Diffusion教程(7) - PS安装AI绘画插件教程
  • 如何学技术
  • 【云存储】使用OSS快速搭建个人网盘教程(阿里云)
  • 微信小程序iconfont真机渲染失败
  • 万界星空/推出生产制造执行MES系统/开源MES/免费下载
  • 【VxWorks】Vxworks、QNX、Xenomai、Intime、Sylixos、Ucos等实时操作系统的性能特点
  • 17、YML配置文件及让springboot启动时加载我们自定义的yml配置文件的几种方式
  • 18、springboot默认的配置文件及导入额外配置文件
  • Conda换源(Linux)
  • 【C语言学习】数据类型转换
  • 深入了解PostgreSQL:高级查询和性能优化技巧
  • 【C#学习笔记】值类型(1)
  • 二十三种设计模式第二十二篇--中介者模式
  • 小研究 - 微服务系统服务依赖发现技术综述(二)
  • javaee 泛型的上下边界和通配符的使用
  • 【TypeScript】类型声明及应用(二)
  • rust from_utf8_lossy怎么使用?
  • #P0997. [NOIP2006普及组] 数列
  • 做完两年外包,感觉自己废了一半....
  • Kubernetes系列-Ingress
  • 软件测试之Docker常见问题汇总!附解决方法!
  • Python-操作Excel表-openpyxl模块使用
  • 向 Maven 中央仓库上传一个修改过的基于jeecg的autoPOI的 jar包记录
  • 【HDFS】Block、BlockInfo、BlockInfoContiguous、BlockInfoStriped的分析记录
  • STM32 LoRa(学习二)
  • ASP.NET Core学习路线图
  • 无涯教程-Lua - for语句函数
  • 二叉树的相关题目