APUE——Chapter 10:信号

2024-05-06 14:58
文章标签 信号 chapter apue

本文主要是介绍APUE——Chapter 10:信号,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

在头文件< signal.h >中,信号名都被定义为正整数常量。 (信号编号)

不存在编号为 0 的信号。

信号处理:
(1)忽略此信号。(有两种信号不能被忽略:SIGKILL、SIGSTOP)。
(2)捕捉信号。(不能捕捉 SIGKILL 和 SIGSTOP 信号)。
(3)执行系统的默认动作。

这里写图片描述

终止+core。大多数Unix系统调试程序都使用core文件检查进程终止时的状态。

在下列条件下不产生core文件:
(a)进程是设置用户ID的,而且当前用户并非程序文件的所有者。
(b)进程是设置组ID的,而且当前用户并非程序文件的组所有者。
(c)用户没有写当前工作目录的权限。
(d)文件已存在,而且用户对该文件没有写权限。

SIGABRT    调用abort函数时产生此信号。
SIGALRM    当用alarm函数设置的定时器超时时,产生此信号。
SIGCHLD    在一个进程终止或停止时,该信号被送给其父进程。按系统默认,将忽略此信号。
SIGFPE     表示算术运算异常,如除以0、浮点溢出等。
SIGHUP     如果终端接口检测到一个连接断开,则将此信号送给与该终端相关的控制进程(会话首进程)。通常使用此信号通知守护进程再次读取它们的配置文件。选用此信号的理由是:守护进程不会有控制终端,通常决不会接收到这种信号。
SIGILL     表示进程执行一条非法硬件指令。
SIGINT     当用户按下中断键Ctrl+C时,终端驱动程序产生此信号并发送至前台进程组的每一个进程。
SIGIO      指示一个异步I/O事件。
SIGTERM    由kill命令发送的系统默认终止信号。
SIGKILL    不能捕获或忽略。它向管理员提供了一红杀死任一进程的可靠方法。
SIGPIPE    如果在管道的读进程已终止时写管道,则产生此信号。
SIGQUIT    当用户在终端上按下退出键Ctrl+\时,终端驱动程序产生此信号并发送给前台进程组中的所有进程。此信号除了终止前台进程组(和SIGINT一样),同时产生一个core文件。
SIGSEGV    指示进程进行了一次无效的内存引用。
SIGTSTP    交互停止信号。当用户在终端上按下挂起键Ctrl+Z时,终端驱动程序产生此信号,并发送至前台进程组的所有进程。
SIGSTOP    类似于交互停止信号(SIGTSTP),但它不能被捕获或忽略。
SIGCONT    此作业控制信号发送给需要继续运行,但当前处于停止状态的进程。
SIGTTIN    当一个后台进程组进程试图读其控制终端时,终端驱动程序产生此信号。下列情况例外:1. 读进程忽略或阻塞此信号;2. 读进程所属的进程组是孤儿进程组,此时读操作返回出错,errno设置为EIO
SIGTTOU    当一个后台进程组进程试图写其控制终端时,终端驱动程序产生此信号。
SIGURG     通知进程已经发生一个紧急情况。如带外数据到达。
SIGUSR1、SIGUSR2  用户定义的信号,可用于应用程序。

10.1 signal函数

#include <signal.h>void (*signal(int signo, void (*func)(int)))(int);/* 返回值:若成功则返回信号以前的处理配置,若出错则返回SIG_ERR */

最好使用sigaction函数代替signal函数

signo:信号名。
func:常量SIG_IGN(指向内核表示忽略此信号)、SIG_DFL(表示接到此信号后的动作是系统默认动作)或当接到此信号后要调用的函数的地址。

子进程继承父进程的信号处理方式(信号捕捉函数的地址在子进程中是有意义的)。

这里写图片描述

没有列入表的大多数函数是不可重入的,原因为:
(a)已知它们使用静态数据结构
(b)它们调用malloc或free
(c)它们是标准I/O函数。

在信号产生(generation)递送(delivery)之间的时间间隔内,称信号是未决的(pending)

每个进程都有一个信号屏蔽字(signal mask),它规定了当前要阻塞递送到该进程的信号集。

进程可调用sigprocmask来检测和更改其当前信号屏蔽字。

10.2 kill和raise函数

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

#include <signal.h>int kill(pid_t pid, int signo);int raise(int signo);/* 两个函数返回值:若成功则返回0,若出错则返回-1 */

pid参数:

pid > 0    将该信号发送给进程ID为pid的进程。
pid == 0   将该信号发送给与发送进程属于同一进程组的所有进程。而且发送进程具有向这些进程发送信号的权限。
pid < 0    将该信号发送给其进程ID等于pid的绝对值,而且发送进程具有向这些进程发送信号的权限。
pid == -1  将该信号发送给发送进程有权限向它们发送信号的系统上的所有进程。

发送权限,基本规则是:发送者的实际或有效用户ID必须等于接收者的实际或有效用户ID

权限测试有一个特例:如果被发送的信号是SIGCONT,则进程可将它发送给属于同一会话的任何其他进程

编号为0的信号定义为空信号

如果signo为0,则kill仍执行正常的错误检查,但不发送信号这常被用来确定一个特定进程是否仍旧存在。如果向一个并不存在的进程发送空信号,则kill返回-1,并将errno设置为ESRCH。

(UNIX系统在经过一段时间后会重新使用进程ID,一个现有的具有所给定进程ID的进程并不一定就是你想要的进程。)

对于进程是否存在这种测试不是原子操作。

10.3 alarm和pause函数

使用alarm函数可以设置一个计时器,在将来某个指定的时间该计时器会超时,则产生SIGALRM信号。默认动作是终止调用该alarm函数的进程。

#include <unistd.h>unsigned int alarm(unsigned int seconds);/* 返回值:0或以前设置的闹钟时间的余留秒数 */

信号由内核产生,由于进程调度的延迟,所以进程得到控制从而能够处理该信号还需一些时间。

每个进程只能有一个闹钟时钟。如果在调用alarm时,以前已为该进程设置过闹钟时钟,而且它还没有超时,则将该闹钟时钟的余留值作为本次alarm函数调用的返回值。以前登记的闹钟时钟则被新值代替。

如果有以前为进程登记的尚未超时的闹钟时钟,而且本次调用的seconds值为0,则取消以前的闹钟时钟,其余留值仍作为alarm函数的返回值。

#include <unistd.h>int pause(void);/* 返回值:-1,并将errno设置为EINTR */

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

只有执行了一个信号处理程序并从其返回时,pause才返回。

10.4 信号集

#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);/* 四个函数返回值:若成功则返回0,若出错则返回-1 */int sigismember(const sigset_t *set, int signo);/* 返回值:若真则返回1,若假则返回0,若出错则返回-1 */

10.5 sigpromask函数

调用sigpromask可以检测或更改其信号屏蔽字,或者一个步骤同时执行这两个操作。

#include <signal.h>int sigpromask(int how, const sigset_t *restrict set, sigset_t *restrict oset);/* 若成功则返回0,若出错则返回-1 */

若oset是非空指针,那么进程的当前信号屏蔽字通过oset返回。

若set是一个非空指针,则参数how指示如何修改当前信号屏蔽字。

这里写图片描述

如果set是空指针,则不改变该进程的信号屏蔽字,how的值也无意义。

在调用sigpromask后如果有任何未决的、不再阻塞的信号,则在sigpromask返回前,至少会将其中一个信号递送给该进程。

10.5 sigpending函数

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

#include <signal.h>int sigpending(sigset_t *set);/* 若成功则返回0,若出错则返回-1 */

10.5 sigaction函数

sigaction函数的功能是检查或修改与指定信号相关联的处理动作(或同时执行这两种操作)。

#include <signal.h>int sigaction(int signo, const struct sigaction *restrict act, struct sigaction *restrict oact);/* 若成功则返回0,若出错则返回-1 */

参数signo是要检测或修改其具体动作的信号编号。

若act为空, 则要修改其动作。

若oact非空,则系统经由oact指针返回该信号的上一个动作。

struct sigaction {void      (*sa_handler)(int);    /* addr of signal handler *//* or SIG_IGN, or SIG_DFL */sigset_t  sa_mask;               /* additional signals to block */int       sa_flags;              /* signal options */void      (*sa_sigaction)(int, siginfo_t *, void *);
}

这里写图片描述

sa_sigaction字段是一个代替的信号处理程序。在sigaction中使用了SA_SIGINFO标志时,使用该信号处理程序。对于sa_sigaction字段和sa_handler字段两者,实现可能使用同一存储区,所以应用只能使用这两个字段中的一个。

通常,按下列方式调用信号处理程序:
void handler(int signo);

但是,如果设置了SA_SIGINFO标志,那么按下列方式调用信号处理程序:
void handler(int signo, siginfo_t *info, void *context);

siginfo_t结构包含了信号产生原因的有关信息。

struct siginfo {int si_signo;    /* signal number */int si_errno;    /* if nonzero, errno value from <errno.h> */int si_code;     /* additional info(depends on signal) */int si_pid;      /* sending process ID */int si_uid;      /* sending process real user ID */int *si_addr;    /* address that caused the fault */int si_status;   /* exit value or signal number */int si_band;     /* band number for SIGPOLL *//* possibly other fields also */
};

下表列出了各种信号的si_code值。

这里写图片描述

10.6 sigsetjmp和siglongjmp函数

#include <setjmp.h>int sigsetjmp(sigjmp_buf env, int savemask);/* 若直接调用则返回0,若从siglongjmp调用返回则返回非0值 */int siglongjmp(sigjmp_buf env, int val);

10.7 sigsuspend函数

#include <signal.h>int sigsuspend(const sigset_t *sigmask);/* 返回值:-1,并将errno设置为EINTR */

10.7 abort函数

#include <stdlib.h>void abort(void);

是异常程序终止。

此函数将SIGABRT信号发送给调用进程。具体方法是raise(SIGABRT)。

10.7 其他

#include <signal.h>void psignal(int signo, const char *msg);/* 类似perror */
#include <string.h>char *strsignal(int signo);/* 类似strerror */
#include <signal.h>int sig2str(int signo, char *str);
int str2sig(const char *str, int* signop);/* 成功返回0,出错返回-1 *//* 它们出错时,并不设置errno */

这篇关于APUE——Chapter 10:信号的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/964664

相关文章

列举你能想到的UNIX信号,并说明信号用途

信号是一种软中断,是一种处理异步事件的方法。一般来说,操作系统都支持许多信号。尤其是UNIX,比较重要应用程序一般都会处理信号。 UNIX定义了许多信号,比如SIGINT表示中断字符信号,也就是Ctrl+C的信号,SIGBUS表示硬件故障的信号;SIGCHLD表示子进程状态改变信号;SIGKILL表示终止程序运行的信号,等等。信号量编程是UNIX下非常重要的一种技术。 Unix信号量也可以

Chapter 13 普通组件的注册使用

欢迎大家订阅【Vue2+Vue3】入门到实践 专栏,开启你的 Vue 学习之旅! 文章目录 前言一、组件创建二、局部注册三、全局注册 前言 在 Vue.js 中,组件是构建应用程序的基本单元。本章详细讲解了注册和使用 Vue 的普通组件的两种方式:局部注册和全局注册。 本篇文章参考黑马程序员 一、组件创建 ①定义 Vue 组件是一种具有特定功能的 Vue 实

Chapter 10 Stability and Frequency Compensation

Chapter 10 Stability and Frequency Compensation Chapter 8介绍了负反馈, 这一章介绍稳定性, 如果设计不好, 负反馈系统是要发生震荡的. 首先我们学习理解稳定判断标准和条件, 然后学习频率补偿, 介绍适用于不同运放的补偿方式, 同时介绍不同补偿对两级运放slew rate的影响, 最后介绍Nyquist’s判断标准 10.1 Gener

Linux中如何屏蔽信号

本篇文章主要学习Linux的信号处理机制,着重学习屏蔽信号部分。屏蔽信号处理的两种方式类似于信号的捕获,一种方式是直接对其设置,另一种方式是先获得描述符的掩码,然后对其设置操作。 本文主要参考自《嵌入式linux系统使用开发》,作者何永琪,Thanks. 在linux系统中,如何处理某个进程发送的一个特定信号呢?一般来说有三种方式: 1) 忽略信号 2) 屏蔽信号 3) 为该信号添

信号与信号量的区别[转]

信号量(Semaphore),有时被称为信号灯,是在多环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。为了完成这个过程,需要创建一个信号量VI,然后将Acquire Semaphore VI以及Release Se

国产隔离放大器:增强信号完整性和系统安全性的指南

隔离放大器是电子领域的关键组件,特别是在信号完整性和电气隔离至关重要的应用中。这些放大器隔离输入和输出信号,使它们能够在没有直接电气连接的情况下跨不同系统传输数据。这确保了电路一部分的高压尖峰或噪声不会影响另一部分,从而保护了系统和用户。随着国产隔离放大器的不断发展,它们提供了性能、可靠性和成本效益的完美结合,使其成为工程师和系统设计师的理想选择。 1. 了解国产隔离放大器的优势 增强信号

信号有效带宽

根据傅里叶变换可以知道信号带宽是无穷大的,这对实际应用是帮助不大的,所以有了有效带宽的概念,可能大家知道常用的经验公式:O.35/Tr或者0.5/Tr等,那这个公式是怎么来的呢?有效带宽又是什么含义呢? 首先来看一个RC低通滤波器,如下: 其上升时间Tr为: 该滤波器的传递函数为: H(s)=1/(RCS+1) 式中S=2πf,转换为频率f的函数为: H(f)=1/(R

Linux 一个简单的中断信号实现

1.查看手册,学习中断处理图 流程:(次级源->开关)到 源挂起 到 开关  到 处理优先级 到 中断挂起标志 到 CPSR里面的开关(图中未展现) 最后cpu处理 此次我们先使用k1按键实现中断,即是eint8 2.此次仅涉及一个中断挂起,步骤较简单,有的寄存器未涉及处理。 寄存器挂起后,通过写1清除对应位( 硬件设计逻辑: 中断标志位通常由硬件自动设置为 1,表示中断发生。

【QT】十分钟全面理解 信号与槽的机制

目录 从一个定时器开始全方位简介1. 基本的信号与槽连接语法例子 2. 使用函数指针连接信号与槽(现代 C++ 风格)语法例子 3. 使用 Lambda 表达式作为槽语法例子 4. 自动连接(`QMetaObject::connectSlotsByName`)规则例子 5. 信号与槽的多对多连接例子(一个信号连接多个槽)例子(多个信号连接一个槽) 6. 断开信号与槽的连接语法例子 7. 信号