Linux-信号3_sigaction、volatile与SIGCHLD

news2024/9/24 17:08:36

文章目录

  • 前言
  • 一、sigaction
    • __sighandler_t sa_handler;
    • __sigset_t sa_mask;
  • 二、volatile关键字
  • 三、SIGCHLD
    • 方法一
    • 方法二


前言

本章内容主要对之前的内容做一些补充。


一、sigaction

#include <signal.h>
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);

之前我们学过signal来对信号进行捕捉,sigaction也是一个对信号进行捕捉的系统接口函数,不过sigaction要相对复杂一些。

参数 int signum 是要捕捉的信号编号。

参数struct* sigaction 在这里作为输入型参数,是提供给我们的一个结构体指针类型,这里的结构体名和函数名相同。

参数struct sigaction *oldact 在这里作为输出型参数。

那么struct sigaction 里面有什么呢?

struct sigaction
  {
    /* Signal handler.  */
#ifdef __USE_POSIX199309
    union
      {
	/* Used if SA_SIGINFO is not set.  */
	__sighandler_t sa_handler;
	/* Used if SA_SIGINFO is set.  */
	void (*sa_sigaction) (int, siginfo_t *, void *);
      }
    __sigaction_handler;
# define sa_handler	__sigaction_handler.sa_handler
# define sa_sigaction	__sigaction_handler.sa_sigaction
#else
    __sighandler_t sa_handler;
#endif

    /* Additional set of signals to be blocked.  */
    __sigset_t sa_mask;

    /* Special flags.  */
    int sa_flags;

    /* Restore handler.  */
    void (*sa_restorer) (void);
  };

我们今天主要对函数体内部的sa_handler和sa_mask进行讨论

__sighandler_t sa_handler;

typedef void __signalfn_t(int);
typedef __signalfn_t *__sighandler_t;

根据__sighandler_t的定义,我们可以知道其本质是一个函数指针,所以这里的我们就可以知道其实本质也是像signal一样使用回调函数来进行信号的捕捉。

__sigset_t sa_mask;

typedef __sigset_t sigset_t;

之前我们在学习sigprocmask和sigaddset等信号集接口函数的时候有过接触sigset_t,那么这里的sa_mask是什么呢?

先提出一个观点,在一个信号被处理(递达)过程中,如果同一个信号再次被发送且进入pending表,那么OS是怎样处理的? OS的处理方式是block(阻塞)相同信号,不再重复递达,等到处理完正在被处理的信号再根据情况决定。 而sa_mask在这里的作用就是可以根据其信号集的有效信号,在signum信号正在被处理时,同时阻塞sa_mask的有效信号和其本身信号。

示例代码如下

#include<iostream>
#include<cstdio>
#include<signal.h>
#include<unistd.h>

void ShowPending()
{
    sigset_t pending;
    sigemptyset(&pending);
    for (int i = 1; i <= 31; i++)
    {
        sigpending(&pending);
        // 通过sigismember来打印我们的pending信号集
        std::cout << sigismember(&pending, i);
    }
    std::cout << std::endl;
}

void catchSig(int signum)
{
    std::cout << "捕捉到" << signum << "信号!" << std::endl; 

    int count = 0;
    while(1)
    {
        ShowPending();
        count++;
        if(count == 50) break;
        sleep(5);
    }
}
int main()
{
    std::cout << "pid: " << getpid() << std::endl;

    //1.定义struct sigaction类型
    struct sigaction act , oldact;

    //2.mask信号集初始化
    sigset_t mask;
    sigemptyset(&mask);

    //3.mask信号集添加1号,2号,3号, 4号,5号,6号作为有效信号
    sigaddset(&mask,1);
    sigaddset(&mask,2);
    sigaddset(&mask,3);
    sigaddset(&mask,4);
    sigaddset(&mask,5);
    sigaddset(&mask,6);

    //4.修改act中的数据
    act.sa_handler = catchSig;
    act.sa_mask = mask;

    //5.调用sigaction
    sigaction(2, &act , &oldact);

    while(1) sleep(1);

    return 0;
}

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

二、volatile关键字

我们之前的学习过程中,也提到过编译器会进行优化,例如我们之前讲的拷贝构造和右值引用都有提到过,而volatile主要解决关于编译器优化所导致的问题。

是的,编译器优化在少数情况下是会造成一些问题的。

而Linux中的gcc编译器是有几种不同程度的优化方案的

-O -O0 -O1 -O2 -O3 -Os -Ofast -Og

在使用gcc或g++命令时,上面的选项从左到右,编译时优化程度依次变大。

示例代码如下

#include<iostream>
#include<cstdio>
#include<signal.h>
#include<unistd.h>

int flag = 0;

void catchSig(int signum)
{
    std:: cout << flag ;
    flag = 1;
    std::cout << "->" << flag <<std::endl; 
}

int main()
{
    signal(2, catchSig);
    while(1)
    {
        if(flag == 1) break;
        ;
    }
    std::cout << "程序正常退出" << std::endl;
    return 0;
}

这段代码如果使用

g++ -o mysignal mysignal.cc -std=c++11

进行编译

结果则是
在这里插入图片描述

这段代码如果使用

g++ -o mysignal mysignal.cc -std=c++11 -O3

进行编译

结果则是
在这里插入图片描述
程序不会自动退出。

这是因为在-O3的优化程度下,编译器检测默认执行流不会修改flag的数据,所以这里的cpu寄存器一直储存着原有的flag值0,导致在判断flag时,一直使用寄存器中的0在判断,导致循环无法退出。

现在我们使用volatile来试试

#include<iostream>
#include<cstdio>
#include<signal.h>
#include<unistd.h>

volatile int flag = 0;

void catchSig(int signum)
{
    std:: cout << flag ;
    flag = 1;
    std::cout << "->" << flag <<std::endl; 
}

int main()
{
    signal(2, catchSig);
    while(1)
    {
        if(flag == 1) break;
        ;
    }
    std::cout << "程序正常退出" << std::endl;
    return 0;
}

在这里插入图片描述
这个时候程序就正常推出了,所以这里volatile的意思就是让告诉编译器不要对flag进行优化,要让寄存器看到内存中的数据!


三、SIGCHLD

SIGCHLD 在子进程停止或者退出时可能收到。

所以我们再学习几种进程等待的方法。

方法一

#include <iostream>
#include <cstdio>
#include <signal.h>
#include <unistd.h>

int main()
{
    signal(SIGCHLD, SIG_IGN);
    pid_t id = fork();
    if(id == 0)
    {
        //子进程
        sleep(10);
        exit(0);
    }

    //父进程
    while(1);
    return 0;
}

将SIGCHLD信号的处理方式变为忽略。
在这里插入图片描述
子进程没有僵尸,而是成功回收。

方法二

#include <iostream>
#include <cstdio>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
void catchCHLD(int signum)
{
    std::cout << "捕捉到SIGCHLD信号!" << std::endl;
    int pid = 0;
    while((pid = waitpid(0,nullptr,WNOHANG)) > 0)
    {
        std::cout << "成功等待" << pid << "号进程" << std::endl;
    }
}

int main()
{
    signal(SIGCHLD, catchCHLD);
    pid_t id = fork();
    if(id == 0)
    {
        //子进程
        sleep(10);
        exit(0);
    }

    //父进程
    while(1);
    return 0;
}

在这里插入图片描述
也同样可以成功回收!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计数排序详解(附源码)

目录 思想&#xff1a; 源码&#xff1a; 思想&#xff1a; 计数排序&#xff1a;用一个数组记录按原始数据中&#xff0c;每个数据出现的次数 非常牛批的思路&#xff0c;没有用到比较 直接对每个数据进行计数 然后从计数的数组中&#xff0c;往回覆盖数据 从左到右&#xf…

解决Qtcreator搜狗输入法无法输入中文问题

由于搜狗输入法依赖fcitx&#xff0c;所以我们解决该问题的核心操作是为QtCreator提供支持fcitx 本系统环境说明&#xff1a;ubuntu22.04、Qt5.12.8、Qt6.6.1&#xff08;我安装了Qt5、Qt6&#xff09; 一、尝试拷贝系统自带libfcitxplatforminputcontextplugin.so到Qt安装目…

科技云报道:阿里云降价,京东云跟进,谁能打赢云计算价格战?

科技云报道原创。 就在大家还在回味2月29日阿里云发布“史上最大降价”的惊喜时&#xff0c;京东云连夜发布降价消息&#xff0c;成为第一家跟进的云服务商&#xff0c;其“随便降&#xff0c;比到底&#xff01;”的口号&#xff0c;颇有对垒的意味&#xff0c;直接吹响了云计…

抖音视频评论批量采集软件|视频下载工具

《轻松搞定&#xff01;视频评论批量采集软件&#xff0c;助您高效工作》 在短视频这个充满活力和创意的平台上&#xff0c;了解用户评论是了解市场和观众心声的重要途径之一。为了帮助您快速获取大量视频评论数据&#xff0c;我们推出了一款操作便捷、功能强大的软件&#xff…

写一个递归函数DigitSum(n),输入一个非负整数,返回组成它的数字之和(C语言)

例如&#xff0c;调用DigitSum(1729)&#xff0c;则应该返回1729&#xff0c;它的和是19 输入&#xff1a;1729&#xff0c;输出&#xff1a;19 int Func(int n) {if (n < 9){return n;}return n % 10 Func(n / 10); } int main() {printf("%d ", Func(12345));r…

链路负载均衡之DNS透明代理

一、DNS透明代理 一般来说&#xff0c;企业的客户端上都只能配置一个运营商的DNS服务器地址&#xff0c;DNS服务器通常会将域名解析成自己所在ISP内的Web服务器地址&#xff0c;这将导致内网用户的上网流量都集中在一个ISP的链路上转发&#xff0c;最终可能会造成链路拥塞&…

Redis基础---Java客户端应用

目录 一、介绍 二、Jedis的使用 三、SpringDataRedis的使用 创建&#xff1a; 一、介绍 在Redis官网&#xff0c;提供了多种编程语言的客户端&#xff0c;如Java、C等&#xff0c;官网地址&#xff1a;Clients | Redis 而对于Java的客户端有很多&#xff0c;但是用的最多的就是…

42、网络编程/多点通信和域套接字通信模型20240304

一、多点通信之广播的收发端实现 1.广播发送端代码&#xff1a; #include<myhead.h>int main(int argc, const char *argv[]) {int sfdsocket(AF_INET,SOCK_DGRAM,0);//创建套接字if(sfd-1){perror("socket,error");return -1;}int broadcast1;//设置套接字广…

【AI视野·今日NLP 自然语言处理论文速览 第八十一期】Mon, 4 Mar 2024

AI视野今日CS.NLP 自然语言处理论文速览 Mon, 4 Mar 2024 Totally 48 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers Mitigating Reversal Curse via Semantic-aware Permutation Training Authors Qingyan Guo, Rui Wang, Junlia…

J013_简易商家外卖系统

一、需求描述 1、完成菜品的上架功能 2、完成菜品的浏览功能 二、开发设计 1、需要设计一个菜品类&#xff0c;用于创建菜品对象 2、需要一个菜品操作类&#xff0c;用于封装菜品上架和菜品浏览功能 3、测试程序 三、代码实现 3.1 Food类 package com.itheima.arrayli…

Linux下安装MinDoc文档

文章目录 背景下载文件将M i n D o c放到目录内解压文件创建数据库配置数据库启动程序演示图 背景 由于日前自己的项目&#xff0c;需要分对外的公开文档&#xff0c; 但是又不想写页面&#xff0c;所以就在网上找了份文档项目。 具体使用步骤如下&#xff1a; 下载文件 请从…

Flutter中Widget的生命周期

Widget生命周期&#xff1a; createState-initState-didChangeDependency-build-deactive-dispose 可通过WidgetsBinding类对widget生命周期的回调进行监控。 createState&#xff1a;StatefulWidget 中用于创建 State&#xff1b; initState&#xff1a;State 的初始化操作&am…

电脑提示bluescreen蓝屏怎么解决? 电脑蓝屏bluescreen修复方法

电脑提示bluescreen蓝屏怎么解决&#xff1f;电脑突然蓝屏提示blueScreen&#xff0c;该怎么解决这个问题呢&#xff1f;下面我们就来分享三种电脑蓝屏bluescreen修复方法&#xff0c;需要的朋友可以参考下 不少朋友都遇到了bluescreen蓝屏的现象&#xff0c;那么出现这种情况…

2.8k star! 用开源免费的edge-tts平替科大讯飞的语音合成服务

edge-tts是github上的一个开源项目&#xff0c;可以免费将文本转为语音&#xff0c;别看它只有2.8k star&#xff0c;替代科大讯飞的收费TTS服务完全没问题&#xff0c;因为这个项目实际是调用的微软edge的在线语音合成服务&#xff0c;支持40多种语言&#xff0c;300多种声音&…

YOLOv8从入门到入土使用教程!(一)训练模型

⭐⭐⭐瞧一瞧看一看&#xff0c;新鲜的YOLOv9魔改专栏来啦&#xff01;⭐⭐⭐ 专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;主力高效涨点&#xff01;&#xff01;&#xff01; 一、本文介绍 本文将演示如何使用YOLOv8进行训练及预测&#xff01; 二…

three.js如何实现简易3D机房?(一)基础准备-上

目录 一、tips 二、功能说明 1.模型初始化 2.功能交互 三、初始化准备 1.目录结构 2.创建三要素 3.创建轨道控制器 4.初始化灯光 5.适配 6.循环渲染 一、tips 1.three.js入门的相关基础性知识就不在此过多赘述了&#xff0c;可以自行提前了解 three.js docs&…

MySql缓冲池命中率

缓冲池 大小查看 show variables like innodb_buffer_pool_size; 太小的innodb_buffer_pool_size是不利于性能的提升 命中率查看 一 、 通过以下命令查看相关数据&#xff1a; show global status like Innodb_buffer_pool_read%;结果如下&#xff1a; 命中率公式&#xff1…

SkyWalking链路追踪上下文TraceContext的追踪身份traceId生成的实现原理剖析

结论先行 SkyWalking 通过字节码增强技术实现&#xff0c;结合依赖注入和控制反转思想&#xff0c;以SkyWalking方式将追踪身份traceId编织到链路追踪上下文TraceContext中。 是不是很有趣&#xff0c;很有意思&#xff01;&#xff01;&#xff01; 实现原理剖析 TraceConte…

bun build

Bun 的快速原生打包器现已进入测试版阶段。可通过 bun build CLI 命令或 Bun.build() JavaScript API 使用。 bun build ./index.tsx --outdir ./build await Bun.build({entrypoints: [./index.tsx],outdir: ./build, }); 速度很快。下面的数字代表 esbuild 在 three.js 基…

PHP+MySQL实现后台管理系统增删改查之够用就好

说明 最近要给博客弄个后台&#xff0c;不想搞得很复杂&#xff0c;有基本的增删改查就够了&#xff0c;到网上找了一圈发现这个不错&#xff0c;很实用&#xff0c;希望可以帮到大家&#xff0c;需要的朋友评论区留下邮箱&#xff0c;我安排发送。 演示效果 项目介绍 本项目…