【Linux】进程间通信之信号机制2

文章目录

  • 信号阻塞代码验证
    • 验证信号的阻塞
    • 验证信号的阻塞不影响信号注册
    • 验证可靠信号不会丢信号,不可靠信号会丢信号
    • 验证9号和19号信号不能被阻塞
  • 用信号解决僵尸进程
  • volatile关键字

信号阻塞代码验证

在上篇详解信号机制的博文中,我们提到了设置阻塞位图的函数sigprocmask函数:

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

现在我们用代码来演示一下:

首先了解一下位图的设置函数:

在这里插入图片描述

验证信号的阻塞

代码如下:

  1 #include <stdio.h>2 #include <unistd.h>3 #include <signal.h>4 void handler(int signum)5 {6   printf("signum : %d\n",signum);7 }8 int main(){9   signal(2, handler);10   sigset_t set;11   sigaddset(&set, 2);                                       12   sigprocmask(SIG_BLOCK, &set, NULL);13   while(1){14     printf("Hello!\n");15     sleep(1);16   }17   return 0;18 }

执行结果:
在这里插入图片描述

验证信号的阻塞不影响信号注册

验证可靠信号不会丢信号,不可靠信号会丢信号

验证思路:

我们选取两个信号2(非可靠信号)、40(可靠信号),首先把这两个信号阻塞,其次再接触这两个信号的阻塞,观察2号信号和40号信号处理几次,同时也证明可靠信号不能丢失信号,非可靠信号会丢失信号

代码如下:

  1 #include <stdio.h>2 #include <unistd.h>3 #include <signal.h>4 void sigcallback(int sig){                                                                                                                               5     printf("sigcallback recv sig: %d\n", sig);6 }                                             7  8 int main(){9   signal(2, sigcallback);10   signal(40, sigcallback);11                           12   sigset_t set;13   sigemptyset(&set);14   sigaddset(&set, 2);15   sigaddset(&set, 40);16                       17   sigprocmask(SIG_BLOCK, &set, NULL);18   getchar();                         19   sigset_t oldset;20   sigemptyset(&oldset);21   sigprocmask(SIG_SETMASK, &oldset, NULL);22                                           23   while(1){       24     printf("i am main, sleep(1)\n");25     sleep(1);                             26   }          27   return 0;28 }        

首先代码是阻塞的,我们发送多次信号,但是都是反应,接着我们随便敲了一个字符,此时启动getchar后面的代码,也就是解除阻塞,此时可以看到程序对之前阻塞了的信号的处理情况

执行结果:

在这里插入图片描述

验证9号和19号信号不能被阻塞

  1 #include <stdio.h>2 #include <unistd.h>3 #include <signal.h>4 void handler(int signum)5 {6   printf("signum : %d\n",signum);    7 }8 9 int main(){10   signal(9, handler);11   signal(19, handler);12 13   sigset_t set;14   sigfillset(&set); // 位图全部置为115 16   sigprocmask(SIG_SETMASK,&set,NULL);17   while(1)18   {19     printf("Hello!\n");20     sleep(1);21   }22 23   return 0;                                             24 }

执行结果:

9号信号和19号信号不执行我自定义的处理方式,依旧按照原有方式处理信号

用信号解决僵尸进程

我们之前在如何解决僵尸问题的时候,提到了用wait或者waitpid函数,但是这两个函数都有不方便的地方,wait函数在调用时,父进程一直处于阻塞等待等待子进程退出状态,waitpid函数需要配合循环,这样的结果就是我们的父进程得不到充分利用,只等着回收子进程退出状态信息了,这里我们可以用信号,对子进程进行回收。

代码如下:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>void sigcallback(int sig){printf("sigcallback recv sig: %d\n", sig);wait(NULL);
}int main(){/** 目的: 解放父进程, 让父进程创建子进程之后, 还能执行父进程的代码逻辑。 并且,还能防止子进程变成僵尸进程** 做法:*    将SIGCHLD信号的处理方式进行自定义*    在自定义的函数当中调用wait/waitpid函数**    子进程退出之后, 会向父进程发送SIGCHLD信号*    父进程回调自定义处理函数, 从调用wait/waitpid函数, 回收子进程的退出状态信息* *//* 1. 自定义处理SIGCHLD信号 */signal(SIGCHLD, sigcallback);/** 2. 创建子进程了* */pid_t ret = fork();perror("fork");if(ret < 0){perror("fork");return 0;}else if(ret == 0){//childsleep(5);printf("i am child\n");}else{ //ret > 0//fatherwhile(1){printf("i am father, exec father process code\n");sleep(1);}}return 0;
}

执行结果:

在这里插入图片描述

volatile关键字

volatile关键字作用:保证内存可见性,告诉编译器,该变量的值可能会在程序的控制之外被修改,因此编译器不应该对该变量的读写进行优化或缓存。每次CPU要计算的数据都是从内存中获取,拒绝编译时优化的方案(从寄存器当中获取),gcc/g++的编译选项“-O0, O1, -O2,-O3“,优化级别越来越高。(理解优化级别越高,程序可能执行的越快)优化级别越高就从寄存器中取值的可能性越大。

代码演示:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>int g_val = 1;void sigcallback(int sig){printf("sigcallback recv sig: %d\n", sig);g_val = 0;
}int main(){signal(2, sigcallback);while(g_val){}printf("hhh, jump down\n");return 0;
}

运行结果:

在这里插入图片描述

上述代码运行按下ctrl+c向进程发送2号信号,进程直接结束了,说明g_val的值被修改了,这是因为我们在编译时没有对程序进行优化,这时候是从内存中拿的

我们试着优化一下,执行结果:

在这里插入图片描述

当我们试着将g_val用volatile关键字声明:

volatile int g_val = 1;

再执行:

在这里插入图片描述
此时优化就不管用了,保证了从内存中读取数据

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/76757.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot中使用validator如何实现接口入参自动检验

文章目录 一、背景二、使用三、举例 一、背景 在项目开发过程中&#xff0c;经常会对一些字段进行校验&#xff0c;比如字段的非空校验、字段的长度校验等&#xff0c;如果在每个需要的地方写一堆if else 会让你的代码变的冗余笨重且相对不好维护&#xff0c;如何更加规范和优…

Vue3 用父子组件通信实现页面页签功能

一、大概流程 二、用到的Vue3知识 1、组件通信 &#xff08;1&#xff09;父给子 在vue3中父组件给子组件传值用到绑定和props 因为页签的数组要放在父页面中&#xff0c; data(){return {tabs: []}}, 所以顶部栏需要向父页面获取页签数组 先在页签页面中定义props用来接…

【仿写tomcat】五、响应静态资源(访问html页面)、路由支持以及多线程改进

访问html页面 如果我们想访问html页面其实就是将本地的html文件以流的方式响应给前端即可&#xff0c;下面我们对HttpResponseServlet这个类做一些改造 package com.tomcatServer.domain;import com.tomcatServer.utils.ScanUtil;import java.io.IOException; import java.io…

马哈鱼数据血缘工具背后的项目: gsp_demo_java 项目简单介绍与使用

0.背景 马哈鱼数据血缘工具(https://www.sqlflow.cn/)是SQLflow工具的中文译名,实际就是sqlflow. 对于SQL flow来说,底层调用的是General SQL Parser(GSP https://sqlparser.com) 的库. 这个gsp有开源的java demo项目:https://github.com/sqlparser/gsp_demo_java 1.快速使用…

4G电力摄像机如何通过AT指令对接到国网平台呢?

对于针对电网安全运行的迫切需求&#xff0c;”输电线路智能可视化监测系统”被研发并应用&#xff0c;通过视频监控和AI智能分析技术&#xff0c;实现了对输电线路远程视频在线监测、外力破坏智能分析&#xff0c;可实现对输电线路的全天候实时监测和预警&#xff0c;有效保障…

阿里云ECS服务器企业级和共享型介绍_企业级常见问题解答FAQ

阿里云企业级服务器是什么&#xff1f;企业级和共享型有什么区别&#xff1f;企业级服务器具有独享且稳定的计算、存储、网络资源&#xff0c;如ECS计算型c6、通用型g8等都是企业级实例&#xff0c;阿里云百科分享什么是企业级云服务器、企业级实例的优势、企业级和共享型云服务…

vue3跳转页面后 海康监控实例不销毁

第一个页面是这样的 跳转到新的页面 只有海康的监控没有消失 使用控制台审查元素也审查不到 解决方法&#xff1a;在vue3的销毁周期把海康的监控销毁掉 import { reactive, onDeactivated} from "vue"; const state reactive({oWebControl: null as any, //监控绑…

kafka晋升之路-理论+场景

kafka晋升之路 一&#xff1a;故事背景二&#xff1a;核心概念2.1 系统架构2.2 生产者&#xff08;Producer&#xff09;2.2.1 生产者分区2.2.2 生产者分区策略 2.3 经纪人&#xff08;Broker&#xff09;2.3.1 主题&#xff08;Topic&#xff09;2.3.2 分区&#xff08;Partit…

攻防世界-warmup

原题解题思路 只有一张图片&#xff0c;就查看源代码&#xff0c;有一个source.php。 查看source.php&#xff0c;白名单中还有一个hint.php。 hint.php告诉我们flag的位置ffffllllaaaagggg 但是直接跳转是没用的&#xff0c;构造payload。 http://61.147.171.105:55725/sourc…

linux部署kafka3.5.1(单机)

一、下载jdk17 kafka3.x版本需要jdk11以上版本才能更好的兼容&#xff0c;jdk11、jdk17都是LTS长期维护版本&#xff0c;而且jdk17支持springboot3.x,所以我选择了openjdk17。 下载地址: Archived OpenJDK GA Releaseshttps://jdk.java.net/archive/ 二、上传jdk安装包解压 …

Netty为什么高效,为什么这么受欢迎?

文章目录 前言Netty 解决的问题简化网络编程粘包和拆包 高性能的设计多线程调度零拷贝 总结 前言 上篇文章通过 Java NIO 的处理流程与 Netty 的总体流程比较&#xff0c;并结合 Netty 的源码&#xff0c;可以更加清晰地理解Netty。本文将结合源码详细解析Netty的高效和强大功…

spring源码分析bean的生命周期(下)

doGetBean()执行过程 createBean()执行过程 一、DependsOn注解 spring创建对象之前会判断类上是否加了DependsOn注解&#xff0c;加了会遍历然后会添加到一个map中&#xff0c;spring会先创建DependsOn注解指定的类 二、spring类加载器 在合并BeanDefinition&#xff0c;确定…