UNIX环境高级编程——信号

news2024/9/28 1:24:23

10.1 引言

  • 信号是软件中断;
  • 信号提供了一种处理异步事件的方法。

10.2 信号概念

  • 每个信号都有一个名字,这些名字都以3个字符SIG开头;
  • 在头文件<signal.h>中,信号名都被定义为正整数常量(信号编号);
  • 不存在编号为0的信号,0编号值称为空信号

当某个信号出现时,可按下列3个方式之一进行处理:
(1)忽略此信号,SIGKILLSIGSTOP这两种信号不能被忽略;
(2)捕捉信号,即在信号发生时,调用一个用户函数;不能捕捉SIGKILLSIGSTOP信号;
(3)执行系统默认动作。
在这里插入图片描述

10.3 函数signal

#include <signal.h>

void (*signal(int signo, void (*func)(int)))(int);
										// 返回值:若成功,返回以前的信号处理配置;若出错,返回SIG_ERR
  • signo参数是信号名;
  • func的值是常量SIG_IGN、常量SIG_DFL或当接到此信号后要调用的函数的地址:
    (1)如果指定SIG_IGN,则向内核表示忽略此信号(SIGKILLSIGSTOP不能忽略);
    (2)如果指定SIG_DFL,则表示接到此信号后的动作是系统默认动作;
    (3)当指定函数地址时,则在信号发生时,调用该函数,称这种处理为捕捉该信号,称此函数为信号处理程序
  • signal函数要求两个参数,返回一个函数指针,该指针所指向的函数无返回值:
    (1)第一个参数signo是一个整型数;
    (2)第二个参数是函数指针,它所指向的函数需要一个整型参数,无返回值;
    (3)signal的返回值是一个函数地址,该函数有一个整型参数;当调用signal设置信号处理程序时,第二个参数是指向该函数(信号处理程序)的指针,返回值则是指向在此之前的信号处理程序的指针。
#define SIG_ERR (void (*)())-1
#define SIG_DFL (void (*)())0
#define SIG_IGN (void (*)())1
  • exec函数将原先设置为要捕捉的信号都更改为默认动作;
  • 当一个进程调用fork时,其子进程继承父进程的信号处理方式。

10.4 不可靠的信号

10.5 中断的系统调用

10.6 可重入函数

10.7 SIGCLD语义

BSD的SIGCHLD信号语义:子进程状态改变后产生此信号,父进程需要调用一个wait函数以检测发生了什么。

10.8 可靠信号术语和语义

  • 产生:当造成信号的事件发生时,为进程产生一个信号;
  • 递送:当一个信号产生时,内核通常在进程表中以某种形式设置一个标志,当对信号采取了这种动作时,称向进程递送了一个信号;
  • 未决的:在信号产生和递送之间的时间间隔内,该信号是未决的;
  • 信号屏蔽字:规定当前要阻塞递送到该进程的信号集合(信号集,sigset_t)。

10.9 函数kill和raise

kill函数将信号发送给进程或进程组,raise函数允许进程向自身发送信号:

#include <signal.h>

int kill(pid_t pid, int signo);
int raise(int signo);
										// 两个函数返回值:若成功,返回0;若出错,返回-1
  • 调用raise(signo)等价于调用kill(getpid(), signo)
  • killpid参数有以下4种不同的情况:
    (1)pid > 0:将该信号发送给进程ID为pid的进程;
    (2)pid == 0:将该信号发送给与发送进程属于同一进程组的所有进程,而且发送进程具有权限向这些进程发送信号;
    (3)pid < 0:将该信号发送给其进程组ID等于pid绝对值,而且发送进程具有权限向其发送信号的所有进程;
    (4)pid == -1:将该信号发送给发送进程有权限向它们发送信号的所有进程。
  • 信号编号0被定义为空信号,如果signo参数是0,则kill仍执行正常的错误检查,但不发送信号,这常被用来确定一个特定进程是否仍然存在;如果向一个并不存在的进程发送空信号,则kill返回-1,errno被设置为ESRCH

10.10 函数alarm和pause

alarm函数可以设置一个定时器(闹钟时间),在将来的某个时刻该定时器会超时,超时产生SIGALRM信号:

#include <unistd.h>

unsigned int alarm(unsigned int seconds);
										// 返回值:0或以前设置的闹钟时间的余留秒数
  • 参数seconds的值是产生信号SIGALRM需要经过的时钟秒数;
  • 每个进程只能有一个闹钟时间;如果在调用alarm时,之前已为该进程注册的闹钟时间还没有超时,则该闹钟时间的余留值作为本次alarm函数调用的值返回,以前注册的闹钟时间则被新值代替;
  • 如果有以前注册的尚未超时的闹钟时间,而且本次调用的seconds值是0,则取消以前的闹钟时间,其余留值仍作为alarm函数的返回值。

pause函数使调用进程挂起直至捕捉到一个信号:

#include <unistd.h>

int pause(void);
										// 返回值:-1,errno设置为EINTR
  • 只有执行了一个信号处理程序并从其返回时,pause才返回,返回-1,errno设置为EINTR

10.11 信号集

信号集是一个能表示多个信号的数据类型,POSIX.1定义数据类型sigset_t以包含一个信号集合,并且定义了下列5个处理信号集的函数:

#include <signal.h>

int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
										// 4个函数返回值:若成功,返回0;若出错,返回-1
int sigismember(const sigset_t *set, int signo);
										// 返回值:若真,返回1;若假,返回0
  • 函数sigemptyset初始化由set指向的信号集,清除其中所有信号;
  • 函数sigfillset初始化由set指向的信号集,使其包含所有信号;
  • 所有应用程序在使用信号集前,要对该信号集调用sigemptysetsigfillset一次;
  • 函数sigaddset将一个信号添加到已有的信号集中;
  • 函数sigdelset则从信号集中删除一个信号。

10.12 函数sigprocmask

函数sigprocmask可以检测或更改,或同时进行检测和更改进程的信号屏蔽字:

#include <signal.h>

int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);
										// 返回值:若成功,返回0;若出错,返回-1
  • oset是非空指针,进程的当前信号屏蔽字通过oset返回;
  • set是一个非空指针,则参数how指示如何修改当前信号屏蔽字:
    在这里插入图片描述
  • 不能阻塞SIGKILLSIGSTOP信号;
  • 如果set是个空指针,则不改变该进程的信号屏蔽字,how的值也无意义。

10.13 函数sigpending

sigpending函数返回一信号集,对于调用进程而言,其中的各信号是阻塞不能递送的,因而也一定是当前未决的:

#include <signal.h>

int sigpending(sigset_t *set);
										// 返回值:若成功,返回0;若出错,返回-1
  • 未决信号集通过set参数返回。

10.14 函数sigaction

sigaction函数的功能是检查或修改(或检查并修改)与指定信号相关联的处理动作:

#include <signal.h>

int sigaction(int signo, const struct sigaction *restrict act, struct sigaction *restrict oact);
										// 返回值:若成功,返回0;若出错,返回-1
  • 参数signo是要检测或修改其具体动作的信号编号;
  • act指针非空,则要修改其动作;
  • 如果oact指针非空,则系统经由oact指针返回该信号的上一个动作。

10.15 函数sigsetjmp和siglongjmp

sigsetjmpsiglongjmp函数用于在信号处理程序中进行非局部转移:

#include <setjmp.h>

int sigsetjmp(sigjmp_buf env, int savemask);
										// 返回值:若直接调用,返回0;若从siglongjmp调用返回,则返回非0
void siglongjmp(sigjmp_buf env, int val);
  • 如果savemask非0,则sigsetjmpenv中保存进程的当前信号屏蔽字;
  • 调用siglongjmp时,如果带非0 savemasksigsetjmp调用已经保存了env,则siglongjmp从其中恢复保存的信号屏蔽字。

当调用一个信号处理程序时,被捕捉到的信号加到进程的当前信号屏蔽字中;当从信号处理程序返回时,恢复原来的屏蔽字。

10.16 函数sigsuspend

sigsuspend函数的功能是在一个原子操作中先恢复信号屏蔽字,然后使进程休眠:

#include <signal.h>

int sigsuspend(const sigset_t *sigmask);
										// 返回值:-1,并将errno设置未EINTR
  • 进程的信号屏蔽字设置为由sigmask指向的值;
  • 在捕捉到一个信号或发生了一个会终止该进程的信号之前,该进程被挂起;
  • 如果捕捉到一个信号而且从该信号处理程序返回,则sigsuspend返回,并且该进程的信号屏蔽字设置为调用sigsuspend之前的值;
  • 此函数没有成功返回值,如果它返回到调用者,则总是返回-1,并将errno设置为EINTR(表示一个被中断的系统调用)。

10.17 函数abort

abort函数的功能是使程序异常终止:

#include <stdlib.h>

void abort(void);
  • 此函数将SIGABRT信号发送给调用进程(进程不应忽略此信号)。

10.18 函数system

10.19 函数sleep、nanosleep和clock_nanosleep

#include <unistd.h>

unsigned int sleep(unsigned int seconds);
										// 返回值:0或未休眠完的秒数
  • 此函数使调用进程被挂起直到满足下面两个条件之一:
    (1)已经过了seconds所指定的墙上时钟时间,返回值是0;
    (2)调用进程捕捉到一个信号并从信号处理程序返回,返回值是未休眠完的秒数。

nanosleep函数与sleep函数类似,但提供了纳秒级的精度:

#include <time.h>

int nanosleep(const struct timespec *reqtp, struct timespec *remtp);
										// 返回值:若休眠到要求的时间,返回0;若出错,返回-1
  • 这个函数挂起调用进程,直到要求的时间已经超时或者某个信号中断了该函数;
  • reqtp参数用秒和纳秒指定了需要休眠的时间长度;
  • 如果某个信号中断了休眠间隔,进程并没有终止,remtp参数指向的timespec结构就会被设置为未休眠完的时间长度;如果对未休眠完的时间并不感兴趣,可以把该参数置为NULL;

clock_nanosleep函数提供了使用相对于特定时钟的延迟时间来挂起调用线程:

#include <time.h>

int clock_nanosleep(clockid_t clock_id, int flags,
					const struct timespec *reqtp, struct timespec *remtp);
										// 返回值:若休眠要求的时间,返回0;若出错,返回错误码
  • clock_id参数指定了计算延迟时间基于的时钟;
  • flags参数用于控制延迟是相对的还是绝对的:
    (1)flags为0时表示休眠时间是相对的;
    (2)如果flags值设置为TIMER_ABSTIME,表示休眠时间是绝对的。

10.20 函数sigqueue

sigqueue函数实现信号排队功能:

#include <signal.h>

int sigqueue(pid_t pid, int signo, const union sigval value);
										// 返回值:若成功,返回0;若出错,返回-1
  • sigqueue函数只能把信号发送给单个进程,可以使用value参数向信号处理程序传递整数和指针值,除此之外,sigqueue函数与kill函数类似。

10.21 作业控制信号

POSIX.1认为有以下6个与作业控制有关:

  • SIGCHLD:子进程已停止或终止;
  • SIGCONT:如果进程已停止,则使其继续运行;
  • SIGSTOP:停止信号(不能被捕捉或忽略);
  • SIGTSTP:交互式停止信号;
  • SIGTTIN:后台进程组成员读控制终端;
  • SIGTTOU:后台进程组成员写控制终端。

10.22 信号名和编号

psignal函数打印与信号编号对应的字符串:

#include <signal.h>

void psignal(int signo, const char *msg);
  • 字符串msg(通常是程序名)输出到标准错误文件,后面跟随一个冒号和一个空格,再后面对该信号的说明,最后是一个换行符;如果msg为NULL,只有信号说明部分输出到标准错误文件。

如果在sigaction信号处理程序中有siginfo结构,可以使用psiginfo函数打印信号信息,它的工作方式与psignal类似:

#include <signal.h>

void psiginfo(const siginfo_t *info, const char *msg);

如果只需要信号的字符描述部分,也不需要把它写到标准错误文件中,可以使用strsignal函数:

#include <string.h>

char *strsignal(int signo);
										// 返回值:指向描述该信号的字符串的指针

Solaris提供一对函数,一个函数将信号编号映射为信号名,另一个则反之:

#include <signal.h>

int sig2str(int signo, char *str);
int str2sig(const char *str, int *signop);
										// 两个函数的返回值:若成功,返回0;若出错,返回-1
  • sig2str函数将给定信号编号翻译成字符串,并将结果存放在str指向的存储区;
  • str2sig函数将给出的信号名翻译成信号编号,该信号编号存放在signop指向的整型中。

10. 23 实例代码

chapter10

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

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

相关文章

架构设计-高性能篇

大家好&#xff0c;我是易安&#xff01;今天我们谈一谈架构设计中的高性能架构涉及到的底层思想。本文分为缓存架构&#xff0c;单服务器高性能模型&#xff0c;集群下的高性能模型三个部分&#xff0c;内容很干&#xff0c;希望你仔细阅读。 高性能缓存架构 在某些复杂的业务…

代码审计笔记之java多环境变量设置

在做java代码审计时&#xff0c;为了要成功运行目标环境&#xff0c;时长要对于jdk版进行切换&#xff0c;且在装多个jdk时还时长会遇到安装配置后环境变量不生效的情况&#xff0c;下文介绍&#xff1b; 1、为什么安装了新的jdk&#xff0c;有的时候环境变量中的jdk版本确还是…

如何设计出好的测试用例?

软件测试培训之如何设计出好的测试用例? 一句话概括&#xff1a;对被测软件的需求有深入的理解。 深入理解被测软件需求的最好方法是&#xff0c;测试工程师在需求分析和设计阶段就开始介入&#xff0c;因为这个阶段是理解和掌握软件的原始业务需求的最好时机。 只有真正理解了…

【VAR模型 | 时间序列】帮助文档:VAR模型的引入和Python实践(含源代码)

向量自回归 (VAR) 是一种随机过程模型&#xff0c;用于捕获多个时间序列之间的线性相互依赖性。 VAR 模型通过允许多个进化变量来概括单变量自回归模型&#xff08;AR 模型&#xff09;。 VAR 中的所有变量都以相同的方式进入模型&#xff1a;每个变量都有一个方程式&#xff…

轻松掌握在已有K8s环境上安装KubeSphere

官方文档地址&#xff1a;https://kubesphere.io/zh/docs/v3.3/quick-start/minimal-kubesphere-on-k8s/ 1、基于已有K8s环境上安装KubeSphere 1、前置环境 1、安装nfs及动态存储类PV/PVC 安装默认存储类型&#xff0c;这里使用nfs&#xff0c;关于nfs的安装在PV/PVC的文章…

出道的第八年,依然AI着......

今天&#xff0c;是数说故事8周岁的生日 8年&#xff0c;和您一起走过2,922天 8年&#xff0c;我们对AI的探索从未停止 8年&#xff0c;我们将数据的热爱进行到底 因为热“AI” 我们与您的故事有了连接 8年的连接&#xff0c;我们与您也擦出了无数花火 我们将每一个闪烁的…

Optional参数类使用

目录 介绍 使用 常用方法 是否为空 对象比较 Optional 是一个对象容器&#xff0c;具有以下两个特点&#xff1a; 使用 1. 创建 2. 获取&#xff1a; 3. 判断&#xff1a; 4. 过滤&#xff1a; 5. 映射&#xff1a; 介绍 在使用值判断的时候使用方便 使用 import j…

linux系统TP-ti,tsc2046外设调试

一、整体调试思路 tp外设属于比较常见且比较简单的外设&#xff0c;今天以ti,tsc2046这款为例简述下tp外设的调试。 整体思路 1、配置设备树----驱动调试的device部分 2、tp驱动编译及匹配—driver部分 3、驱动整体调试 二、配置设备树 对于ti,tsc2046我们可以参考内核Docum…

复杂美科技多项区块链技术产品被纳入《2021-2022区块链产业图谱》区块链蓝皮书

2022年9月3日&#xff0c;由中国社会科学院社会科学文献出版社、北京金融科技产业联盟指导&#xff0c;北京区块链技术应用协会&#xff08;BBAA&#xff09;主办的 “Web 3.0发展趋势高峰论坛暨2022元宇宙、区块链、金融科技蓝皮书发布会” 在服贸会上成功举办。 大会隆重发布…

身份鉴别解读与技术实现分析(1)

6.1.4.1 身份鉴别 本项要求包括: a) 应对登录的用户进行身份标识和鉴别,身份标识具有唯一性,身份鉴别信息具有复杂度要求并定期更换; b) 应具有登录失败处理功能,应配置并启用结束会话、限制非法登录次数和当登录连接超时自动退出等相关措施 在等级保护体系中,级别越高…

数字时代下网络安全的重要性

在数字时代&#xff0c;网络安全比以往任何时候都更加重要。 随着我们越来越依赖技术来存储和传输敏感信息&#xff0c;网络攻击的风险也在增加。网络攻击可能来自世界任何地方&#xff0c;对个人和企业都可能是毁灭性的。 AkamaiTechnologies首席安全官BoazGelbord在最近的一…

【YOLO系列】YOLOv7论文超详细解读(翻译 +学习笔记)

前言 终于读到传说中的YOLOv7了~≖‿≖✧ 这篇是在美团的v6出来不到一个月就高调登场&#xff0c;作者还是我们熟悉的AB大神&#xff08;对&#xff0c;就是v4那个&#xff09;&#xff0c;读起来又是“熟悉”的感觉&#xff08;贯穿了我的整个五一假期&#xff08;╯&#x…

Vue组件设计-多列表拖拽交换排序

在前端开发中&#xff0c;拖拽排序是一种提升用户体验非常好的方式&#xff0c;常见的场景有单列表拖拽排序&#xff0c;多列表拖拽交换排序&#xff0c;比如以下这种效果&#xff1a; 下面将以这种效果为例&#xff0c;设计一个组件。 1. 安装所需依赖 npm install vuedragg…

多模态的过渡态——latent modal

背景&#xff1a; 随着大模型的推进&#xff0c;单模态的大模型已经无法很好的满足现实工作的需要。很多科研团队和机构开始多模态的研究&#xff0c;多模态的几种机构在前面的文章已经介绍过&#xff0c;这部分不做过多介绍。最理想的多模态应该就是没有模态&#xff0c;单一…

持续集成/持续交付——JenkinsFile详细使用教程

JenkinsFile详细使用教程 一、BlueOcean1、BlueOcean 概念2、BlueOcean 特性3、BlueOcean 安装 二、Pipeline 简介1、Jenkins Pipeline 概念2、Jenkinsfile 语法类型&#xff1a;3、采用Jenkins 任务页面输入a. Jenkins中创建一个 pipeline 任务b. Definition 中选择 Pipeline …

电脑提示msvcp140.dll丢失的解决方法,msvcp140.dll丢失修复教程

msvcp140.dll是Microsoft Visual C Redistributable所需的一个动态链接库文件&#xff0c;它包含了Visual C运行库中的一些函数和类库。这个文件通常出现在Windows操作系统中&#xff0c;用于支持使用Visual C编写的程序的正常运行。如果系统缺少或损坏了这个文件&#xff0c;可…

计算机组成原理 4.2.1存储芯片连接

连接原理 主存储器 通过数据总线、地址总线和控制总线和CPU相连数据总线的位数正比于数据传输率地址总线的位数决定可寻址的最大地址空间控制总线(读/写)指出总线周期的类型和本次输入/输出完成的时刻 但是实际中存储芯片往往很小难以满足地址和数据的位数需求&#xff0c;此…

如何在云服务器上搭建ChatGLM

摘录&#xff1a;ChatGPT重新点燃了AI&#xff0c;然后OpenAI却没有向我们开放ChatGPT&#xff0c;虽然有些人通过了一下手段注册了账号&#xff0c;但是不久就被OpenAI拉入了黑名单。3月份我国的百度也推出了和ChatGPT对标的文言一心&#xff0c;随后阿里也推出了自己的文本对…

李雨浛:在数据、网络与民意之间——用计算社会科学方法探讨数字媒体与可持续未来 | 提升之路系列(八)...

导读 为了发挥清华大学多学科优势&#xff0c;搭建跨学科交叉融合平台&#xff0c;创新跨学科交叉培养模式&#xff0c;培养具有大数据思维和应用创新的“π”型人才&#xff0c;由清华大学研究生院、清华大学大数据研究中心及相关院系共同设计组织的“清华大学大数据能力提升项…

创建并使用shell脚本

1&#xff0c;查询 bash解释器 所在位置 创建前&#xff0c;我们需要先知道 bash 解释器所在的位置&#xff0c;以方便在头部写声明。一般位置是在 /bin/bash 但是有的是在 /usr/bin/bash &#xff0c;所以需要查找一下。 文件位置查找命令&#xff1a;whereis xxx rootarmb…