- 浏览: 142380 次
文章分类
最新评论
注:本文摘自《深入理解计算机系统》第8章 --- 异常控制流。本文不适于不了解信号的人,在此也不对信号做过多解释,只是个人需要记录相关的信号处理问题而已,想了解更详细的请自行查阅相关资料。
程序只捕获一个信号时是简单直接的,但当要捕获多个信号时,就可能产生一些细微的问题。
1、待处理信号被阻塞。unix信号处理程序通常会阻塞当前处理程序正在处理的类型的待处理信号。比如,假设一个进程捕获了SIGCHLD信号(注:每个子进程终止或退出时,内核都会发送一个SIGCHLD信号给父进程),并且当前正在运行它的SIGCHLD处理程序,如果另一个 SIGCHLD 信号传递到这个进程,那么这个信号将变成待处理的,但不会被接收,直到处理程序返回。
2、待处理信号不会排队等待。任意类型至多只有一个待处理信号。因此,如果有两个类型为k的信号传送到一个目的进程,而由于目的进程当前正在执行信号k的处理程序,所以信号k是阻塞的,那么第二个信号就被简单地丢弃,它不会排队等待。关键思想是存在一个待处理的信号仅仅表明至少已经有一个信号到达了。
3、系统调用可以被中断。像read、wait 和 accpet 这样的系统调用潜在地会阻塞一段较长的时间,称为慢系统调用。在某些系统中,当处理程序捕获到一个信号时,被中断的慢速系统调用在信号处理程序返回时不再继续,而是立即返回给用户一个错误条件,并将error设置为EINTR。
我知道,要看懂这几句话可能不用例子只怕很难理解,所以想了下,还是把例子抄上来好些。
解释:父进程设置了一个SIGCHLD处理程序,然后创建了三个子进程,其中每个子进程运行1秒,然后终止。同时,父进程等待来自中端的一个输入行,随后处理它。这个处理被模型化为一个无限循环,当每个子进程终止时,内核通过发送一个SIGCHLD信号通知父进程,父进程捕获这个信号,回收一个子进程,做一些其它的清除工作,然后返回。
但当在linux上运行时,输出是类似这样的:
从中可看出,尽管发送了3个SIGCHLD信号给父进程,但是其中只有两个信号被接收了,因此父进程只是回收了两个子进程。此时若挂起父进程,用ps命令查看一下,可看到进程10321没有被回收,而是成为了一个僵尸进程。
为何会这样?尽管这个程序看似很正常,但其实它是有缺陷的,因为它无法处理信号阻塞、信号不排队等待和系统调用被中断这些情况。它实际发生的情况是:父进程接收并捕获了第一个信号,当处理程序还在处理第一个信号时,第二个信号就传送并添加到了待处理信号集合里。但因为信号SIGCHLD信号被SIGCHLD处理程序阻塞了,所以第二个信号就不会被接收。此后不久,就在处理程序还在处理第一个信号时,第三个信号到达了。因为已经有了一个待处理的SIGCHLD,所以第三个SIGCHLD信号会被丢弃。一段时间后,处理程序返回,内核注意到有一个待处理的SIGCHLD信号,就迫使父进程接收该信号。父进程捕获它,并第二次执行处理程序。在处理程序完成对第二个信号的处理后,已经没有待处理的SIGCHLD信号了,而且也绝不会再有,因为第三个SIGCHLD的所有信息都已经丢失了。所以教训是绝不可以用信号来对其它进程中发生的事件计数!
为了修正这个问题,必须想到存在一个待处理的信号只是暗示自进程最后一次收到一个信号以来,至少已经有一个这种类型的信号被发送了,所以必须修改SIGCHLD处理程序,使得每次SIGCHLD处理程序被调用时,回收尽可能多的僵尸子进程。在此只需修改SIGCHLD处理程序,其余的保持原样:
现在再次运行,结果就能回收所有僵尸子进程了,在此偷个懒就不贴运行结果了。
然而,革命尚未成功!本程序能够正确解决信号会阻塞和不会排队等待的情况,但它没有考虑系统调用被中断的可能性。在有些系统上,在从键盘上进行输入之前,被阻塞的read系统调用就提前返回一个错误:
出现这个问题是因为在特定的Solaris系统上,诸如read这样的慢速系统调用在被信号发送中断后,是不会自动重启的。相反,和linux系统自动重启被中断的系统调用不同,它们会提前返回给调用程序一个错误条件。修改时只要它能手动地重启被终止的read调用即可,本次需要修改主函数:
程序只捕获一个信号时是简单直接的,但当要捕获多个信号时,就可能产生一些细微的问题。
1、待处理信号被阻塞。unix信号处理程序通常会阻塞当前处理程序正在处理的类型的待处理信号。比如,假设一个进程捕获了SIGCHLD信号(注:每个子进程终止或退出时,内核都会发送一个SIGCHLD信号给父进程),并且当前正在运行它的SIGCHLD处理程序,如果另一个 SIGCHLD 信号传递到这个进程,那么这个信号将变成待处理的,但不会被接收,直到处理程序返回。
2、待处理信号不会排队等待。任意类型至多只有一个待处理信号。因此,如果有两个类型为k的信号传送到一个目的进程,而由于目的进程当前正在执行信号k的处理程序,所以信号k是阻塞的,那么第二个信号就被简单地丢弃,它不会排队等待。关键思想是存在一个待处理的信号仅仅表明至少已经有一个信号到达了。
3、系统调用可以被中断。像read、wait 和 accpet 这样的系统调用潜在地会阻塞一段较长的时间,称为慢系统调用。在某些系统中,当处理程序捕获到一个信号时,被中断的慢速系统调用在信号处理程序返回时不再继续,而是立即返回给用户一个错误条件,并将error设置为EINTR。
我知道,要看懂这几句话可能不用例子只怕很难理解,所以想了下,还是把例子抄上来好些。
void handler1(int sig){ pid_t pid; if((pid=waitpid(-1, NULL, 0)) < 0) unix_error("waitpid error"); printf("Handler reaped child %d\n", (int)pid); Sleep(2); return; } int main(){ int i, n; char buf[MAXBUF]; if(signal(SIGCHLD, handler1) == SIG_ERR) unix_error("signal error"); for(i=0; i<3; i++){ if(Fork() == 0){ printf("Hello from child %d\n", (int)getpid()); Sleep(1); exit(0); } } if((n=read(SIGIN_FILENO, buf, sizeof(buf))) < 0) unix_error("read"); printf("Parent processing input\n"); while(1){ ; } exit(0); }
解释:父进程设置了一个SIGCHLD处理程序,然后创建了三个子进程,其中每个子进程运行1秒,然后终止。同时,父进程等待来自中端的一个输入行,随后处理它。这个处理被模型化为一个无限循环,当每个子进程终止时,内核通过发送一个SIGCHLD信号通知父进程,父进程捕获这个信号,回收一个子进程,做一些其它的清除工作,然后返回。
但当在linux上运行时,输出是类似这样的:
linux> ./signal1 Hello from child 10320 Hello from child 10321 Hello from child 10322 Handler reaped child 10320 Handler reaped child 10322 <cr> Parent processing input
从中可看出,尽管发送了3个SIGCHLD信号给父进程,但是其中只有两个信号被接收了,因此父进程只是回收了两个子进程。此时若挂起父进程,用ps命令查看一下,可看到进程10321没有被回收,而是成为了一个僵尸进程。
为何会这样?尽管这个程序看似很正常,但其实它是有缺陷的,因为它无法处理信号阻塞、信号不排队等待和系统调用被中断这些情况。它实际发生的情况是:父进程接收并捕获了第一个信号,当处理程序还在处理第一个信号时,第二个信号就传送并添加到了待处理信号集合里。但因为信号SIGCHLD信号被SIGCHLD处理程序阻塞了,所以第二个信号就不会被接收。此后不久,就在处理程序还在处理第一个信号时,第三个信号到达了。因为已经有了一个待处理的SIGCHLD,所以第三个SIGCHLD信号会被丢弃。一段时间后,处理程序返回,内核注意到有一个待处理的SIGCHLD信号,就迫使父进程接收该信号。父进程捕获它,并第二次执行处理程序。在处理程序完成对第二个信号的处理后,已经没有待处理的SIGCHLD信号了,而且也绝不会再有,因为第三个SIGCHLD的所有信息都已经丢失了。所以教训是绝不可以用信号来对其它进程中发生的事件计数!
为了修正这个问题,必须想到存在一个待处理的信号只是暗示自进程最后一次收到一个信号以来,至少已经有一个这种类型的信号被发送了,所以必须修改SIGCHLD处理程序,使得每次SIGCHLD处理程序被调用时,回收尽可能多的僵尸子进程。在此只需修改SIGCHLD处理程序,其余的保持原样:
void handler2(int sig){ pid_t pid; while((pid = waitpid(-1, NULL, 0)) > 0){ printf("Handler reaped child %d\n", (int)pid); } if(error != ECHILD) unix_error("waitpid error"); Sleep(2); return; }
现在再次运行,结果就能回收所有僵尸子进程了,在此偷个懒就不贴运行结果了。
然而,革命尚未成功!本程序能够正确解决信号会阻塞和不会排队等待的情况,但它没有考虑系统调用被中断的可能性。在有些系统上,在从键盘上进行输入之前,被阻塞的read系统调用就提前返回一个错误:
solaris> ./signal2 Hello from child 18906 Hello from child 18907 Hello from child 18908 Handler reaped child 18906 Handler reaped child 18908 Handler reaped child 18907 read: Interrupted system call
出现这个问题是因为在特定的Solaris系统上,诸如read这样的慢速系统调用在被信号发送中断后,是不会自动重启的。相反,和linux系统自动重启被中断的系统调用不同,它们会提前返回给调用程序一个错误条件。修改时只要它能手动地重启被终止的read调用即可,本次需要修改主函数:
int main(){ int i, n; char buf[MAXBUF]; pid_t pid; if(signal(SIGCHLD, handler1) == SIG_ERR) unix_error("signal error"); for(i=0; i<3; i++){ if((pid=Fork()) == 0){ printf("Hello from child %d\n", (int)getpid()); Sleep(1); exit(0); } } whileda((n=read(SIGIN_FILENO, buf, sizeof(buf))) < 0){ if(errno != EINTR) unix_error("read"); } printf("Parent processing input\n"); while(1){ ; } exit(0); }
发表评论
-
浮点运算指令
2019-05-22 23:13 1575上一节介绍了浮点数与各种数值类型之间的相互转换 ... -
浮点数类型转换指令
2019-05-15 22:37 1710在浮点寄存 ... -
浮点寄存器概述
2019-05-14 22:31 2590本文介绍的浮点寄存器是基于 AVX2(Adva ... -
汇编指令之跳转指令
2019-04-15 00:21 4799正常执行的情况下,指令会按照顺序一条条地执行, ... -
汇编指令之条件码
2019-04-08 21:05 2359在系统底层,除了整数寄存器,CPU 还维护着一 ... -
汇编指令之算术和逻辑操作指令
2019-03-28 22:16 1382下表是 x86-64 ... -
汇编指令之数据传送指令
2019-03-25 21:28 1288在x86-64 中的 ... -
x86-64 中的寄存器与汇编操作数杂述
2019-03-20 21:45 993Intel 中常用 ... -
hello 程序执行背后的故事
2018-12-26 21:48 608源文件 hello. ... -
linux启动服务概述
2017-04-08 02:43 398传统的linux中定义了七个运行级,分别如下: ... -
unix限制
2017-04-04 16:08 579UNIX系统实现定义了很多幻数和常量,其中有很 ... -
linux引导加载程序--GRUB
2017-04-04 04:22 625linux世界里有两种 ... -
存储器映射
2016-06-13 00:12 553注:本文摘自《深入理解计算机操作系统》第九章--虚拟存 ... -
虚拟存储器对存储器管理的作用
2016-06-10 16:00 695注:本文中的大部分内容均是摘录自《深入理解计算机系统》一书,权 ... -
僵尸进程
2016-05-23 23:57 361在解释僵尸进程的概念之前,我们得先了解这样的一个事实: 一个进 ... -
程序优化之存储器别名使用
2016-05-20 08:55 797说明:本文示例摘自《深入理解计算机系统》第五章----优化程序 ... -
条件变量基本概念与原理(转载)
2016-05-20 08:54 1580对于条件变量,我一直感到很困惑,搞不清其与互斥锁到底有啥区别, ... -
CPU与磁盘的交互过程
2016-05-19 09:05 1840对于计算机系统底层技术,想必很多人都和我一样不太了解,最近在学 ... -
存储器层次结构中基本的缓存原理
2016-05-19 09:00 668对于操作系统,我们知道,越靠近CPU的存储器,其存储速度就会越 ... -
异常处理
2016-05-19 00:29 424我知道很多人都知道异常处理,但可能对其底层并不太了解,现在我们 ...
相关推荐
丁美玉的答案集可能涵盖了上述知识点的习题解答,通过解答这些题目,学习者能够加深对理论知识的理解,提升实际操作技能,并掌握如何将理论应用于实际的信号处理问题。这份资源对于学习和研究数字信号处理的学者来说...
MATLAB是一种广泛应用于科学计算、数据分析、算法开发和系统建模的高级编程环境。在信号处理领域,MATLAB因其强大的数学运算能力和丰富的...通过熟练掌握MATLAB的信号处理功能,用户能够高效地解决各种信号处理问题。
14. 实际应用中的数字信号处理问题:讨论在实际应用中遇到的数字信号处理问题和挑战,例如实现高效算法、数字信号处理器编程、实时信号处理等。 以上是数字信号处理领域的一些基础和高级知识点。为了更好地复习和...
例如,答案可能包含了解决特定信号处理问题的步骤,如如何使用离散傅立叶变换(DFT)来分析周期性信号,或者如何设计IIR滤波器实现特定频率响应。 在"现代数字信号处理"中,关键知识点包括: 1. **数字信号的基本...
通过这些知识点,我们可以了解到统计信号处理的一些核心概念和方法,以及它们在实际信号处理问题中的应用。实际上,文件中提及的大部分知识点都是信号处理领域的基础理论,对于理解和设计实际的信号处理系统有着重要...
数字信号处理是电子信息技术中的一个核心领域,它涉及使用数字方法对信号进行分析、处理和...通过理解这些知识点,能够更好地把握数字信号处理的技术发展趋势,并在实际工作中有效地应用这些技术解决各种信号处理问题。
压缩包中的eg3_1.m到eg3_6.m文件可能分别对应于不同的信号处理问题和算法实现,例如DOA估计、干扰对消、波束形成等。每个文件可能包含一个特定的优化问题的求解过程,比如使用特定的自适应算法解决实际问题。 7. *...
在IT领域,阵列信号处理是一门至关重要的技术,它主要应用于雷达、通信、声纳等领域,用于提高信号检测...通过深入学习和实践这些算法,你将能够处理更复杂的信号处理问题,提高系统性能,并为未来的创新打下坚实基础。
1. 文件名包含"ans"的PDF文件,如dsp试题L1_01ans.pdf,很可能是对应练习题的答案解析,其中可能涵盖了解决数字信号处理问题的具体步骤、公式推导以及计算过程。 2. 文件名不包含"ans"的PDF文件,如dsp试题L1_01.pdf...
《数字信号处理》是电子工程领域的一门重要课程,它主要研究如何在数字域内对信号进行分析、处理和变换...通过深入学习和解决这些习题,读者将能够熟练掌握数字信号处理的基础知识,并具备解决复杂信号处理问题的能力。
习题解答在这些高级主题的应用中起到了桥梁的作用,帮助学生理解复杂的概念,并能够将这些概念应用于解决实际的信号处理问题。 综上所述,习题解答文件不仅仅是一份简单的答案汇编,它是一种学习资源,对学生掌握...
习题可能要求计算这些统计量,理解它们的关系,并应用到实际信号处理问题中。 此外,书中可能还会涵盖其他主题,如多速率信号处理、数字信号的压缩与编码,以及现代数字信号处理的应用,如通信、图像处理和音频处理...
《数字信号处理》第三版是高西全和丁玉美合著的一本教材,主要针对时域离散信号和时域离散系统进行深入讲解。本章内容是学习数字信号处理的...扎实掌握这些基础,将使学习者在面对复杂的数字信号处理问题时更有信心。
《信号处理中的线性代数》则是从矩阵和向量的角度探讨信号处理问题,线性代数是理解和解决多变量系统的基础,它在滤波器设计、特征提取和系统建模等领域具有重要作用。 最后,《非平稳信号分析与处理》聚焦于那些...
这些习题旨在帮助读者巩固所学知识,并通过实际操作来提高解决数字信号处理问题的能力。 《MATLAB数字信号处理》不仅可作为高等院校数字信号处理相关课程的教学参考教材,而且也可以作为科研人员在相关领域的技术...
4. 实例学习:"matlab数字信号处理实例.pdf"很可能包含了各种具体的信号处理问题的MATLAB代码实例,如滤波器设计、信号的频谱分析、噪声抑制、信号恢复等。通过这些实例,学习者可以理解如何在MATLAB环境中编写和...
【数字信号处理】是电子工程和通信领域的重要分支,主要涉及对数字形式的信号进行分析、变换、滤波和处理的技术。...通过实践,读者能够更好地掌握数字信号处理的核心概念,并应用于实际的信号处理问题中。
学生通过本章的学习,将能够熟练运用这些基本运算来解决复杂的信号处理问题。 第四章则涵盖了数字信号的抽取、插值和多速率信号处理。这部分内容对于理解和实现高效的信号处理系统至关重要,特别是在采样率转换和...
在数字信号处理领域,MATLAB是一种广泛使用的工具,它提供了丰富的库函数和强大的计算能力,使得信号的分析、...通过不断实践和探索,我们可以利用MATLAB解决复杂的信号处理问题,例如噪声抑制、信号恢复、特征提取等。
《数字信号处理教程》程佩青第三版是深入学习数字信号处理领域的经典教材。...通过对压缩包内文件a301d80e05794b68b79b4d2e17e72879的阅读,读者可以更深入地理解和掌握这些概念,并应用到实际的信号处理问题中。