`

信号基础函数

阅读更多
    signal 函数可为特定的信号指定信号处理函数,可以是常量 SIG_IGN(表示忽略,但 SIGKILL 和 SIGSTOP 信号不能忽略)、SIG_DFL(表示使用默认处理动作,多数为终止)或自定义的信号处理函数地址。
#include <signal.h>
void (*signal(int signo, void (*func)(int)))(int);
          /* 返回值:若成功,返回该信号以前的信号处理函数地址;否则,返回 SIG_ERR */

#define SIG_ERR    (void (*)())-1
#define SIG_DFL    (void (*)())0
#define SIG_IGN    (void (*)())1

    其中,signo 参数是信号名,func 是信号处理函数的地址。由于该函数原型过于复杂,可使用 typedef 来使其简单一些:
            typedef void Sigfunc(int);
            Sigfunc *signal(int, Sigfunc *);
    常量 SIG_ERR、SIG_DFL 和 SIG_IGN 在 <signal.h> 在的定义表示“指向函数的指针,该函数要求一个整型参数,而且无返回值”。
    当执行一个程序时,通常所有信号都被设置为它们的默认动作,除非调用 exec 的进程忽略该信号。确切地讲,exec 函数将原先设置为要捕捉的信号都更改为默认动作,其他信号的状态则不变,因为原先的信号捕捉函数的地址很可能在所执行的新程序文件中已无意义。
    一个具体例子是一个交互 shell 如何处理针对后台进程的中断和退出信号。通常 shell 会自动将后台进程对中断和退出信号的处理方式设置为忽略,否则当按下中断字符时,它不但会终止前台进程,也终止所有后台进程。
    很多捕捉这两个信号的交互程序都具有下列形式的代码:
...
void sig_int(int), sig_quit(int);
if(signal(SIGINT, SIG_IGN) != SIG_IGN)
    signal(SIGINT, sig_int);
if(signal(SIGQUIT, SIG_IGN) != SIG_IGN)
    signal(SIGQUIT, sig_quit);
...

    这样处理后,仅当 SIGINT 和 SIGQUIT 当前未被忽略时,进程才会捕捉它们。
    而当一个进程调用 fork 时,其子进程一般会继承父进程的信号处理方式。因为子进程是复制的父进程内存映像,所以信号捕捉函数的地址在子进程中是有意义的。

    kill 函数将信号发送给进程或进程组,raise 函数则允许进程向自身发送信号。
#include <signal.h>
int kill(pid_t pid, int signo);
int raise(int signo);
                  /* 返回值:若成功,都返回 0;否则,都返回 -1 */

    kill 的 pid 参数有以下 4 种不同的情况。
    (1)pid > 0:将该信号发送给进程 ID 为 pid 的进程。
    (2)pid == 0:将该信号发送给与发送进程属于同一进程组的所有进程,要求发送进程具有向这些进程发送信号的权限。
    (3)pid < 0:将该信号发送给其进程组 ID 等于 pid 绝对值,而且发送进程具有发送信号权限的所有进程。
    (4)pid == -1:将该信号发送给发送进程具有发送信号权限的所有进程。
    注意,这里的“所有进程”不包括实现定义的系统进程集(如内核进程和 init)。至于发送信号的权限,超级用户可将信号发送给任一进程,而对于非超级用户,其基本规则是发送者的实际用户 ID 或有效用户 ID 必须同接收者的一样。如果实现支持 _POSIX_SAVED_IDS,则检查接收者的保存设置用户 ID 而不是有效用户 ID。不过在对权限进行测试时也有一个特例:如果被发送的信号是 SIGCONT,则进程可将它发送给同一会话的任一其他进程。
    POSIX.1 将信号编号 0 定义为空信号。如果 signo 参数是 0,则 kill 仍执行正常的错误检查,但不发送信号。如果向一个并不存在的进程发送空信号,则 kill 返回 -1,并把errno 置为 ESRCH,这常被用来测试一个特定进程是否仍然存在(不过由于进程 ID 具有可复用性,以及该测试操作并非原子操作,所以这种测试并无多大价值)。
    如果调用 kill 为调用进程产生信号,而且此信号是不被阻塞的,那么在 kill 返回之前,signo 或者某个其他未决的、非阻塞信号就被传送至该进程。

    函数 alarm 可以设置一个定时器,当超时时会产生 SIGALRM 信号,其默认动作是终止调用进程。而函数 pause 可以使调用进程挂起直到捕捉到一个信号,只有执行了一个信号处理程序并从其返回时,pause 函数才返回。
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
                       /* 返回值:0 或以前设置的闹钟时间的余留秒数 */
int pause(void);       /* 返回值:-1,并把 errno 设置为 EINTR */

    每个进程只能有一个闹钟时间。如果在调用 alarm 时,之前已注册的闹钟时间还没有超时,则该闹钟剩余的时间将作为本次 alarm 函数的值返回,而以前注册的闹钟时间则被新值替代。当参数 seconds 的值是 0 时,则会取消以前的闹钟时间,但剩余的时间仍作为 alarm 的值返回。另外,如果想捕捉 SIGALRM 信号,则应在调用 alarm 之前安装该信号的处理程序,以免在安装之前就已接到该信号使进程终止。

    信号编号可能会超过一个整型的位数,因此 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 */

    其中,函数 segemptyset/sigfillset 初始化 set 指向的信号集,使其清除/包括所有信号,函数 sigaddset/sigdelset 则用于向其中添加/删除一个信号。
    每个进程都有一个信号屏蔽字,它规定了当前要阻塞的信号集,可以调用 sigprocmask 函数来检测和更改当前的信号屏蔽字。
#include <signal.h>
int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);
                                     /* 返回值:若成功,返回 0;否则,返回 -1 */

    其中,若参数 oset 是非空指针,则进程的当前信号屏蔽字就通过它返回;若 set 是个空指针,则不改变该进程的信号屏蔽字,此时 how 的值也无意义;若 set 是非空指针,则 how 指示如何修改当前信号屏蔽字,其可选值如下表。

    当产生一个信号时,内核通常会在进程表中设置一个标志。在信号产生和递送之间的时间间隔内,称信号是未决的(pending)。进程可以选用“阻塞信号递送”。如果为一个进程产生了一个阻塞的信号,而且对该信号的动作是系统默认动作或捕捉,则将此信号保持为未决状态,直到对此信号解除了阻塞,或者将动作更改为忽略。内核在递送一个原来被阻塞的信号给进程时,才决定对它的处理方式,所以进程在信号递送给它之前仍可改变对该信号的动作。
    进程可以调用 sigpending 函数来判定哪些信号是设置为阻塞并处于未决状态的。该函数通过 set 参数返回一信号集,对于调用进程而言,其中的各信号是阻塞不能递送的,因而也一定是当前未决的。
#include <signal.h>
int sigpending(sigset_t *set);    /* 返回值:若成功,返回 0;否则,返回 -1 */

    如果在进程解除对某个信号的阻塞之前,这种信号发生了多次,则 POSIX.1 允许系统递送该信号一次或多次。如果递送了多次,则称这些信号进行了排队。不过除非支持 POSIX.1 实时扩展,否则大多数 UNIX 并不对信号排队,而是只递送这种信号一次。当有多个信号要递送给一个进程时,POSIX.1 并没规定它们的递送顺序,只是建议在其他信号之前递送与进程当前状态有关的信号,如 SIGSEGV。
    下面这个程序展示了上面提到的很多信号功能(忽略了很多函数调用检查):进程阻塞 SIGQUIT 信号,保存了当前信号屏蔽字以便后面恢复,然后休眠 5 秒,在此期间所产生的退出信号 SIGQUIT 都被阻塞,不递送至该进程,直到该信号不再被阻塞。在 5 秒休眠结束后,检查该信号是否是未决的,然后将 SIGQUIT 设置为不再阻塞。
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

static void sig_quit(int signo){
	printf("caught SIGQUIT\n");
	signal(SIGQUIT, SIG_DFL);
}

int main(void){
	sigset_t	newmask, oldmask, pendmask;
	if(signal(SIGQUIT, sig_quit) == SIG_ERR){
		printf("can't catch SIGQUIT\n");
		exit(1);
	}
	/* Block SIGQUIT and save current signal mask */
	sigemptyset(&newmask);
	sigaddset(&newmask, SIGQUIT);
	sigprocmask(SIG_BLOCK, &newmask, &oldmask);
	sleep(5);		// SIGQUIT here will remain pending

	sigpending(&pendmask);
	if(sigismember(&pendmask, SIGQUIT))
		printf("\nSIGQUIT pending\n");
	
	/* Restore signal mask which unblock SIGQUIT */
	sigprocmask(SIG_SETMASK, &oldmask, NULL);
	printf("SIGQUIT unblocked\n");
	sleep(5);		// SIGQUIT here will terminate with core file
	exit(0);
}

    运行结果如下:
$ ./sigmask.out 
^\                           # 5 秒内产生 SIGQUIT 信号一次
SIGQUIT pending              # 从 sleep 返回后
caught SIGQUIT               # 在信号处理程序中
SIGQUIT unblocked            # 从 sigprocmask 返回后
^\退出 (core dumped)         # 再次产生信号
$ 
$ ./sigmask.out 
^\^\^\^\^\^\^\^\^\           # 5 秒内多次产生 SIGQUIT 信号
SIGQUIT pending
caught SIGQUIT               # 只捕获一次
SIGQUIT unblocked
^\退出 (core dumped)         # 再次产生信号

    这里,在休眠期间如果产生了退出信号,那么此时该信号是未决的,但不再受阻塞,所以在 sigprocmask 返回前,它被递送到调用进程,因此 SIGQUIT 处理程序中的 printf 语句先于 sigprocmask 之后的 printf 语句前执行。然后该进程再休眠 5 秒。如果在此期间再产生退出信号,那么因为在上次捕捉到该信号时,已将其处理方式设置为默认动作,所以这一次它就会使该进程终止。注意,第二次运行该程序时,在进程休眠期间产生了多次 SIGQUIT 信号,但解除了对该信号的阻塞后,只向进程传送一次 SIGQUIT,从中可以看出此系统上没有将信号排队。
  • 大小: 7.4 KB
分享到:
评论

相关推荐

    matlab语音信号处理函数

    PCM(Pulse Code Modulation,脉冲编码调制)是数字音频的基础,是一种广泛采用的模拟信号数字化的方法。本文将深入探讨MATLAB中的语音信号处理函数以及PCM编码的原理与应用。 首先,MATLAB提供了丰富的语音信号...

    LFMCW雷达信号模糊函数分析_杨建宇.pdf

    通过分析LFMCW雷达信号模糊函数与脉冲雷达信号模糊函数的差异,有助于揭示LFMCW雷达在体制理论方面的独特内涵,对运动目标回波的分析表明了距离速度耦合以及波形畸变的现象,这为提高LFMCW雷达的探测性能和优化雷达...

    Boost变换器的CCM_DCM小信号传递函数.pdf

    ### Boost变换器的CCM/DCM小信号传递函数解析 #### 一、引言 在电力电子领域,Boost变换器作为一种重要的DC-DC转换器,被广泛应用于各种电子设备和系统中。为了精确地分析和设计Boost变换器,了解其小信号行为变得...

    MATLAB信号处理函数说明

    - `rectpuls` 产生非周期的矩形波形,是数字信号处理的基础。 - `sawtooth` 和 `sinc` 分别生成锯齿波和 sinc 函数,常用于滤波器设计。 - `square` 产生方波,常见于电子电路和通信系统。 2. **滤波器分析和...

    chap2_LFM_Ambiguity_Fuction_LFM脉冲信号的模糊函数推导_振荡衰减_

    这暗示了对LFM脉冲信号模糊函数的理解可能不够全面,需要进一步深入探讨其数学基础和物理意义。振荡衰减通常是指在模糊函数的图像中,随着τ(时间差)和fd(多普勒频移)的变化,函数值会呈现周期性的振荡,并随...

    数字信号处理的函数库

    采样与重构是数字信号处理的基础,确保了模拟信号与数字信号之间的转换。窗口函数用于改善信号的频谱分辨率,减少处理中的副作用。而自相关和互相关函数则用于分析信号的统计特性,如周期性、相关性等。 在实际开发...

    多功能智能函数信号发生器

    多功能智能函数信号发生器在保留合成信号发生器优点的基础上,通过引入DDS和DSP技术,有效克服了寄生分量的问题,提高了信号的纯净度和可控性。 #### 结论 综上所述,多功能智能函数信号发生器集成了多项先进技术...

    Signals and Systems\matlab基本信号处理函数及实例.rar

    《信号与系统——MATLAB基础信号处理函数及实例》 信号与系统是电子工程、通信、计算机科学等领域的核心课程,而MATLAB作为强大的数值计算和可视化工具,被广泛用于信号处理的教学和研究。本资料重点讲解MATLAB在...

    确定信号matlabM函数文件_swamsdl_matlab_MySin_正弦衰减_典型信号_

    矩形脉冲是信号处理中基础的测试信号,它通常用于研究系统响应或作为滤波器的输入。MATLAB的`impulse`函数可以生成单位脉冲,而`MyImpulse`可能提供了更多的自定义选项,如脉冲宽度、幅度或位置。这种灵活性对于理解...

    exe_OFDM-LFM_信号模糊函数_OFDM模糊函数_ofdm模糊函数_OFDM模糊函数.zip

    为了深入研究,你需要具备数字信号处理、OFDM理论、雷达信号处理和至少一种编程语言的基础知识。解压并分析这些源码将提供宝贵的实践经验,有助于理解OFDM-LFM信号在实际应用中的行为,以及如何利用模糊函数来优化...

    matlab中数字信号处理所用函数定义库.rar

    自定义函数可能扩展了这些基础功能,提供更复杂或特定的应用场景的滤波器。 2. **傅里叶变换**:除了fft和ifft,自定义函数可能包含了窗函数傅里叶变换、多维傅里叶变换或者快速傅里叶变换的优化实现。 3. **信号...

    数字信号处理常用函数整理

    在数字信号处理领域,函数是实现各种操作的基础工具。这些函数涵盖了从波形生成、滤波分析到系统变换等多个方面。下面将详细解释标题和描述中提到的一些关键知识点。 1. **波形产生和绘图**: - `chirp` 用于生成...

    函数信号发生器实验报告(信号与系统)

    实验报告的主题围绕着“函数信号发生器”,这是电子工程领域常用的一种设备,用于产生不同类型的模拟信号,如...这对于深入学习信号与系统这一学科至关重要,因为理解和控制信号生成是分析、设计和测试电子系统的基础。

    模糊函数仿真.zip_信号匹配_信号模糊函数_匹配滤波_模糊函数_模糊函数仿真

    在电子工程和信号处理领域,模糊函数和匹配滤波是两个关键的概念,它们在许多应用中都有着广泛的应用,如通信、雷达系统、图像处理等。本文将深入探讨这两个概念以及它们在仿真中的实现。 首先,我们要理解“模糊...

    正弦函数信号发生器的设计

    【正弦函数信号发生器的设计】是一门EDA技术及应用的课程设计,旨在让学生通过实践掌握数字系统设计的基础知识和技能。在这个项目中,学生需要使用EDA工具Quartus II来设计一个基于Cyclone系列FPGA的正弦波信号发生...

    典型信号matlabM函数文件_matlab;典型信号;M函数文件;_tri是方波吗_m函数三角波_

    本压缩包包含三个M函数文件,分别用于生成三种典型的周期性信号:三角波(MyTri)、方波(MySquare)和准周期信号(MyStdPeriod)。下面将详细介绍这三个函数及其相关知识点。 首先,我们来看`MyTri.m`函数,它实现...

    函数信号发生器课程设计报告

    函数信号发生器是一种重要的电子设备,它能够在不同的频率范围内生成各种标准波形,如方波、三角波和正弦波,广泛应用于科研...通过这样的设计,学生能够掌握信号发生器的关键技术,为今后的电子系统设计打下坚实基础。

    函数信号发生器c语言

    标题 "函数信号发生器c语言" 指的是使用C语言编程实现的一种设备或软件,能够在给定参数下生成各种类型的模拟或数字信号。在51单片机上实现这样的功能,意味着我们需要深入理解51单片机的硬件特性、I/O口操作以及...

    实验二Python语言基础函数包练习.docx

    Python 语言基础函数包练习 本文档主要介绍 Python 语言基础函数包的使用,包括 math、NumPy、SciPy 和 Matplotlib 等函数包的应用。实验目的在于熟练掌握 Python 语言基础函数包的使用,并通过实践 exercise,提高...

    exe_OFDM-LFM_信号模糊函数_OFDM模糊函数_ofdm模糊函数_OFDM模糊函数_源码.rar

    在深入研究这个源码之前,你需要具备一些基础知识,包括OFDM的基本原理、LFM信号的生成和特性,以及如何处理无线通信中的多径传播问题。源码可能涵盖了以下知识点: 1. OFDM系统的基本结构,包括子载波的分配、IFFT...

Global site tag (gtag.js) - Google Analytics