《Linux C编程实战》笔记:信号的屏蔽

在《Linux C编程实战》笔记:信号的捕捉和处理-CSDN博客的sigaction的sa_mask成员,它的类型就是一个信号集,下面我们来介绍它

信号集

信号的总数目达64个,所以不能用一个整数表示它们的集合,int类型通常是4字节32位,位数不够。POSIX标准定义了数据类型sigset_t来表示信号集,并且定义了一系列函数来操作信号集

#include<signal.h>
//初始化一个信号集,使其不包括任何信号
int sigemptyset(sigset_t *set);//初始化一个信号集,使其包括所有信号
int sigfillset(sigset_t *set);//向set指定的信号集中添加由signun指定的信号
int sigaddset(sigset_t *set,int signum);//从set指定的信号集中删除由signum指定的信号
int sigdelset(sigset_t *set,int signum);//测试信号signum是否包括在set指定的信号集中
int sigismember(const sigset_t *set,int signum);

前四个函数在执行成功时返回0,失败返回-1.

sigismember返回1表示测试的信号在信号集中,返回0表示信号不在信号集中,出错返回-1.

注意:在使用信号集前,要对信号集调用一次sigemptyset或sigfillset来初始化它。

信号屏蔽

信号屏蔽又称信号阻塞

#include<signal.h>
int sigprocmask(int how,const sigset_t *set,sigset *oldset);
int sigpending(sigset_t *set);
int sigsuspend(const sigset_t *mask);

sigprocmask函数 

每一个进程都有一个信号屏蔽码,调用sigprocmask可以修改进程的信号屏蔽码。

当信号被屏蔽时,如果有一个或多个屏蔽的信号到达,它们会被挂起,直到信号解除屏蔽。信号解除屏蔽后,挂起的信号会被递送给进程,但如果信号在解除屏蔽前多次到达,不可靠信号只会递送一次,可靠信号会按次数递送。

  • how:此参数确定如何更改信号掩码。它可以取以下值之一:

    • SIG_BLOCK:将集合中的信号添加到当前信号掩码。
    • SIG_UNBLOCK:从当前信号掩码中移除集合中的信号。
    • SIG_SETMASK:将信号掩码设置为指定的集合。
  • set:这是一个指向 sigset_t 对象的指针,表示要阻塞、解除阻塞或设置的信号集,具体取决于 how 参数的值。

  • oldset:这是一个可选的指向 sigset_t 对象的指针,用于存储先前的信号掩码。如果为 NULL,则不保存先前的信号掩码。

sigprocmask 的返回值在成功时为 0,在失败时为 -1,同时设置 errno 以指示错误。

sigpending函数

函数sigpending函数用来获取调用进程因被阻塞但已经产生的未决信号集。该信号集通过参数set返回。

成功返回0,有错误发生返回-1,错误代码存入errno。

示例程序1

该程序演示了sigprocmask和sigpending的用法

#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>
//自定义的错误处理函数,这个以前都讲过
void my_err(const char *err_string,int line){fprintf(stderr,"line:%d ",line);perror(err_string);exit(1);
}
//SIGINT的信号处理函数
void handler_sigint(int signo){printf("recv SIGINT\n");
}
int main(int argc,char **argv){//定义了几个信号集sigset_t newmask,oldmask,pendmask;//安装信号处理函数if(signal(SIGINT,handler_sigint)==SIG_ERR)//安装失败的错误处理,这个SIG_ERR在signal这一节也讲过my_err("signal",__LINE__);//这里可以发送SIGINT信号测试一下,这时候是可以响应的sleep(10);sigemptyset(&newmask);//初始化newmasksigaddset(&newmask,SIGINT);//将SIGINT添加进去if(sigprocmask(SIG_BLOCK,&newmask,&oldmask)<0)//尝试将SIGINT添加到进程的屏蔽屏蔽码中去,用的是SIG_BLOCKmy_err("sigprocmask",__LINE__);else printf("SIGINT blocked\n");sleep(10);//睡一会//获取未决的信号队列,我们操作的时候应该在睡眠的时候发送一次SIGINT信号来测试if(sigpending(&pendmask)<0)my_err("sigpending",__LINE__);//用sigismember查看未决信号集里是否有SIGINTswitch (sigismember(&pendmask,SIGINT)){case 0:printf("SIGINT is not in pending queue\n");break;case 1:printf("SIGINT is in pending queue\n");break;case -1:my_err("sigismember",__LINE__);break;default:break;}//再解除对SIGINT的屏蔽,就是把原先的信号屏蔽码又设置回去if(sigprocmask(SIG_SETMASK,&oldmask,nullptr)<0)my_err("sigprocmask",__LINE__);else printf("SIGINT unblocked\n");while(1);return 0;
}

看运行结果,一开始我发送SIGINT,信号处理函数有用,然后SIGINT被阻塞了,这时候我发了四个SIGINT,根据不可靠信号的阻塞,最后只有一个信号会被递送,所以程序只打印了一次recv SIGINT,之后阻塞解除,我再发送SIGINT也可以正常接收。

sigsuspend函数

sigsuspend 函数用于临时修改信号屏蔽字(signal mask)并挂起进程,直到收到一个信号为止。

函数的作用可以分为两步:

  1. 临时替换当前信号屏蔽字为 mask
  2. 挂起进程,直到接收到一个信号。

当进程接收到一个信号后,sigsuspend 会恢复原始的信号屏蔽字,并返回。这个函数通常用于实现原子操作,即在某些关键操作期间阻塞特定的信号,以确保该操作不会被信号中断。

这个函数总是返回-1,并将errno置为EINTR

示例程序2

#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>
void my_err(const char *err_string,int line){fprintf(stderr,"line:%d ",line);perror(err_string);exit(1);
}
void handler_sigint(int signo){printf("\nrecv SIGINT\n");
}
int main(int argc,char **argv){sigset_t newmask,oldmask,zeromask;if(signal(SIGINT,handler_sigint)==SIG_ERR)my_err("signal",__LINE__);sigemptyset(&newmask);sigemptyset(&zeromask);sigaddset(&newmask,SIGINT);if(sigprocmask(SIG_BLOCK,&newmask,&oldmask)<0)my_err("sigprocmask",__LINE__);else printf("SIGINT blocked\n");//前面和上一个示例都是一样的/*临界区*///使用sigsuspend取消所有信号的屏蔽并等待信号的触发,因为zeromask是空的信号集if(sigsuspend(&zeromask)!=-1)//sigsuspend总是返回-1my_err("sigsuspend",__LINE__);else printf("recv a signo,return from sigsuspend\n");/*------------------------------//使用sigprocmask加上pause可能会出现错误if(sigprocmask(SIG_SETMASK,&oldmask,nullptr)<0)my_err("sigprocmask",__LINE__);pause();---------------------------*///下面也是一样,恢复屏蔽字if(sigprocmask(SIG_SETMASK,&oldmask,nullptr)<0)my_err("sigprocmask",__LINE__);else printf("SIGINT unblocked\n");while(1);return 0;
}

程序首先用sigprocmask屏蔽掉信号SIGINT,然后使用sigsuspend()取消对所有信号的屏蔽,并挂起等待信号的触发。

然后随便发送一个信号

这是按书上的步骤,不过我觉得问题很大,书上随便发了个SIGRTMIN的信号,但是由于我们没有给这个信号注册信号处理函数,所以进程默认直接结束了。这句话也没有执行 :  else printf("recv a signo,return from sigsuspend\n");

这回我们发SIGINT信号

虽然进程一开始屏蔽了SIGINT信号,但是我们调用了sigsuspend函数,并且这个例子里的sigsuspend函数的信号集是空的,它会取消对所有信号的屏蔽,然后挂起,所以我们发送SIGINT进程这时是可以接收的。可以看到进程首先调用了SIGINT的处理函数,之后sigsuspend函数返回-1(函数返回前会把屏蔽字恢复成原来的情况,也就是SIGINT被阻塞),执行了之前没有执行的打印语句。

如果使用注释掉的那段代码,会有风险。如果信号发生在sigprocmask之后pause之前,则这个信号可能就会丢失了,如果信号只发生一次,程序将永远挂起在pause上。

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

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

相关文章

CKA考试练习题

一&#xff1a;为部署管道创建一个新的 ClusterRole 并将其绑定到范围为特定 namespace 的特定 ServiceAccount 要求&#xff1a;创建一个名字为 deployment-clusterrole 且仅允许创建以下&#xff08;Deployment&#xff0c;StatefulSet &#xff0c;DaemonSet&#xff09;资源…

Linux | makefile简单教程 | Makefile的工作原理

前言 在学习完了Linux的基本操作之后&#xff0c;我们知道在linux中编写代码&#xff0c;编译代码都是要手动gcc命令&#xff0c;来执行这串代码的。 但是我们难道在以后运行代码的时候&#xff0c;难道都要自己敲gcc命令嘛&#xff1f;这是不是有点太烦了&#xff1f; 在vs中…

力扣646. 最长数对链

动态规划 思路&#xff1a; 思路与 力扣354. 俄罗斯套娃信封问题 类似将序列进行排序&#xff0c;然后假设 dp[i] 为第 i 个元素的最长数对链个数&#xff1b;则其状态转移方程&#xff1a; 第 i 个元素之前的某一个元素&#xff08;假设是下标是 j&#xff09;&#xff0c;如…

SPEC CPU 2017 Qemu RISCV

SPEC CPU 2017 Qemu RISCV 以下是 SPEC CPU 2017 的官方描述, 据说在 1.1.9 版本之后支持 RISCV SPEC CPU 2017 may be updated from time to time. To update your copy, use runcpu --update. History: v1.1.9, Nov-2022: Add RISC-V Linux toolset; update sysinfo.v1.1.8, …

KVM部署Alibaba Cloud Linux操作系统

下载镜像文件 下载链接&#xff1a;https://mirrors.aliyun.com/alinux/image/?spma2c4g.11186623.0.0.79ed5af6pehv54 下载文件&#xff1a;aliyun_3_x64_20G_nocloud_alibase_20230727.qcow2 部署KVM虚拟化环境 yum -y install qemu libvirt rr-testsuite systemctl star…

[SUCTF 2019]CheckIn1

黑名单过滤后缀’ph&#xff0c;并且白名单image类型要有对应文件头 对<?过滤&#xff0c;改用GIF89a<script languagephp>eval($_POST[cmd]);</script>&#xff0c;成功把getshell.gif上传上去了 尝试用.htaccess将上传的gif当作php解析&#xff0c;但是失败…

常见的前端打包构建工具有哪些

Webpack&#xff1a; Webpack 是一个模块打包工具&#xff0c;它能够将各种资源&#xff08;JavaScript、CSS、图片等&#xff09;打包成一个或多个静态文件&#xff0c;以优化加载性能。 Parcel&#xff1a; Parcel 是一个零配置的前端打包工具&#xff0c;可以自动识别项目中…

Flutter Text文字下方出现黄色双下划线

在Flutter中&#xff0c;Text组件是属于Material风格的&#xff0c;这就要求我们的根组件最好也是Material风格的&#xff0c;否则UI展示可能会有一些问题。刚刚提到的启动页&#xff0c;根组件直接使用的层叠布局Stack&#xff0c;而Stack就不属于Material风格&#xff0c;当S…

美工前端和数据对接一起做的可视化大屏开发项目工期一周足矣

hello宝子们...我们是艾斯视觉擅长ui设计和前端开发10年经验&#xff01;希望我的分享能帮助到您&#xff01;如需帮助可以评论关注私信我们一起探讨&#xff01;致敬感谢感恩&#xff01; 可视化大屏已经成为企业和组织中不可或缺的一部分。它不仅可以帮助企业更好地展示业务数…

[docker] Docker的私有仓库部署——Harbor

一、Docker原生私有仓库—— Registry 1.1 Registry的简单了解 关于Docker的仓库分为私有库和公有仓库&#xff0c;共有仓库只要在官方注册用户&#xff0c;登录即可使用。但对于仓库的使用&#xff0c;企业还是会有自己的专属镜像&#xff0c;所以私有库的搭建也是很有必要的…

jQuery实现选择方法和保护信息方法

最近呢&#xff01;一直在学习jQuery语法&#xff0c;也没时间发布文章&#xff0c;现在学的差不多了&#xff0c;先跟大家分享下学习感受吧&#xff01;JavaScript学过后&#xff0c;再学习jQuery语法&#xff0c;应该是简单的&#xff0c;但我总是容易把它们搞混&#xff0c;…

开源模型部署及使用

开源模型部署及使用 1.Langchain-Chatchat1.环境2.运行3.效果 2.facefusion1.环境2.运行3.效果 3.Aquila1.环境2.运行 1.Langchain-Chatchat Langchain-Chatchat这里面可以调用许多模型&#xff0c;我本地下载了chatglm3模型文件&#xff0c;所以就用这个模型。 1.环境 根据…

牛客网---------[USACO 2016 Jan S]Angry Cows

题目描述 Bessie the cow has designed what she thinks will be the next big hit video game: "Angry Cows". The premise, which she believes is completely original, is that the player shoots cows with a slingshot into a one-dimensional scene consistin…

实现负载均衡

1.安装依赖 sudo apt insta11 libgd-dev 2.下载nginx wget http://nginx.org/download/nginx-1.22.1.tar.gz 3.解压nginx tar -zvxf nginx-1.22.1.tar.g2 4.编译安装 cd nginx-1.22.1 5.编译并指定安装位置&#xff0c;执行安装之后会创建指定文件夹/www/env/nginx ./configure…

【大数据】流处理基础概念(二):时间语义(处理时间、事件时间、水位线)

流处理基础概念&#xff08;一&#xff09;&#xff1a;Dataflow 编程基础、并行流处理流处理基础概念&#xff08;二&#xff09;&#xff1a;时间语义&#xff08;处理时间、事件时间、水位线&#xff09;流处理基础概念&#xff08;三&#xff09;&#xff1a;状态和一致性模…

使用pysimplegui+opencv编写一个摄像头的播放器

需求 使用pysimplegui和opencv实现一个播放器&#xff0c;播放 摄像头的画面。 代码实现 import cv2 import time from typing import Iterable, NamedTuple, Optionalimport PySimpleGUI as sgclass CameraSpec(NamedTuple):name: strindex: intwidth: intheight: intfps: i…

c# ADODB.Recordset实例调用Fields报错

代码&#xff1a; using System; using System.CodeDom; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using ADODB;namespace ConsoleApp1 {internal class Programre{static ADODB.Recordset recordsetInstance…

代码随想录刷题笔记 DAY15 | 翻转二叉树 No.226 | 对称二叉树 No.101

Day 15 01. 翻转二叉树&#xff08;No. 226&#xff09; 题目链接 代码随想录题解 1.1 题目 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9…

GPU无进程但显存占用

在服务器的docker里面使用显卡发现在终端 ctrl c之后&#xff0c;代码会停掉但是GPU资源不会释放。 nvidia-smi里面还看不到PID进程号&#xff0c;有PID号直接kill 就行了 如果想要把GPU上所有程序全都杀掉可以执行下面的命令 fuser -v /dev/nvidia* |awk {for(i1;i<NF;i…

Odoo14 中的小部件列表

们有不同类型的小部件用于不同的目的&#xff0c;帮助我们简化操作。小部件用于使代码变得简单且用户友好&#xff0c;这将有助于软件的编码和编程方面。在 Odoo 14 开发中&#xff0c;我们可以利用不同的小部件&#xff0c;这些小部件可用于编程操作的某些特定方面。这些简化工…