信号和信号处理

本文详细介绍了Linux中的信号机制,包括信号的基本概念、产生方式、处理方法及其影响。信号是一种进程间通信方式,通过kill命令和系统调用可以发送信号。进程对信号有三种处理方式:忽略、捕捉并自定义处理函数、执行默认动作。信号处理函数的设置和信号发送有特定规则,如SIGKILL和SIGSTOP不能忽略。此外,文章还探讨了信号处理中的重入问题、原子操作、中断系统调用,以及如何设置和使用信号处理函数、定时器和挂起进程。
摘要由CSDN通过智能技术生成
1. 信号的基础


       信号时一种常用的Linux进程间的通信方式,用户进程使用的Linux命令中有许多包含对信号的处理。深入讨论常用的Linux信号时有必要的,可以通过查询帮助文档的方式查询。


1.1 信号的基本概念


       信号时一种进程通信的方式,又称为软中断,一个进程一旦收到信号就会打断原来的程序执行流程来处理该信号。由于进程不知道你是否收到信号,因此,信号通过这种进程间的通信方式是异步的。任何一个进程都可以发送信号并且接收信号。使用 kill -l 命令可以查看系统所支持的信号列表。


       kill-l 能够查看信号的编号以及信号对应的宏。这些宏定义在signal.h中。信号编号从1号开始,所以没有0号信号。每个信号的具体意义可以使用Linux系统内带有的man命令查询。


1.2 产生信号


       Linux环境下共有以下5种方式可以产生信号:


       1. 用户按下某些终端键时,终端驱动程序会发送信号给前台进程,例如 Ctrl+C 产生SIGINT信号,Ctrl+\ 产生SIGQUIT 信号。在用户需要终止一个进程时经常使用这些信号。


       2. 硬件异常产生信号,这些条件由硬件检测到并通过内核,然后内核向当进程发送适当的信号。例如,被0 除后产生SIGFPE 异常信号,无效内存访问产生SIGSEGV 信号,这就是在Linux环境下开发应用程序经常遇到的段错误。


       3. 一个进程调用 kil(2) 函数可以发送信号给另一个进程


       4. 可以用 kill(1) 命令发送信号给某个进程,kill(1) 命令也是调用 kill(2)函数实现的,如果不明确指定信号则发送 SIGTERM信号。kill 命令常用的使用方法是杀掉一个进程,许多人根据其命令的名判断它的功能。其实杀死一个进程只是kill 命令功能极小的一部分,是其向指定进程发送SIGTERM信号的结束。


       5. 当内核检测到某软件条件发生时,也可以通过信号通知进程,例如,闹钟时间超时产生SIGALRM,该信号是由alarm函数所设置的定时器发送的。


       不论是上述5种方法中那一种发送了信号,接收信号的进程都会暂停执行程序,转而处理接收到的信号。如果进程处于就绪状态,那么一旦进程得到CPU时间片将首先处理信号。如果进程处于挂起状态,那么接收信号将唤醒挂起进程,进程将首先处理信号。


1.3 处理信号


       对于一个信号,Linux环境下的进程只有三种处理方式:


        1. 忽略此信号,对其置之不理


        2. 注册一个信号处理函数,并要求内核在接收到信号时切换到用户态用该处理函数,这种方式称为捕捉到一个信号。用户程序经常需要对某些信号做一些自定义的处理,例如,如果进程创建了临时文件,那么可能要为SIGTERM 信号编写一个信号处理函数以清除临时文件,这样被 kill 时也可以比较干净地终止。


        3. 执行系统默认动作。不同的信号有不同的系统默认动作,系统所使用的默认动作只有两种。终结进程或者忽略信号。


 


2. 信号的影响


       信号是一种传统的、方便的通信方式。当进程捕捉到信号时,不论进程当前执行到何处,都会先跳到信号处理函数中执行,从信号处理函数返回后再恢复先前的代码位置继续执行。因此信号也会产生一个副作用。


2.1 重入


       当进程捕捉到信号时,不论进程当前执行到何处,都会跳到信号处理函数中执行,从信号处理函数返回后再恢复先前的代码位置继续执行。信号处理函数此时进程执行到何处。


       在同一进程中,main函数(主线程)、其他线程以及信号处理函数都是各自独立的执行流程,它们是并行。如果一个进程有多个执行流程,并且这些执行流程访问相同的全局资源(全局变量等),就有可能出现冲突。


       如果一个函数被不同的执行流程调用,有可能第一次调用还没返回就又一次进入该函数,则称为重入,这个函数访问一个全局的链表,有可能因为重入而造成错乱,称为不可重入函数。反之,如果一个函数只访问局部变量或参数,则称为可重入(reentrant)函数或者纯代码,或称为线程安全(thread-safe) 的函数。


       如果一个函数符号以下条件之一则是不可重入的:


       1. 使用了全局的数据,例如全局变量或静态变量


       2. 调用了动态方法得到内存(调用malloc函数),因为动态分配内存的方法也是以链表来管理内存分配的,这种数据也是全局作用域的


       3. 使用了标准 I/O 库,标准 I/O 库的很多实现都以不可重入的方式使用全局数据结构


       所以,归根结底所有使用具有全局作用域的数据都是函数,都是不可重入的,这种函数代码被chengwi非纯代码。


2.2 原子操作


       原子类型 sig_atomic_t


       C语言提供了volatile 限定符,如果将变量定义为volatile sig_atmoic_t a=0;那么即使制定了优化选项,编译器不会优化选项,编译器也不会优化掉对变量a内存单元的读写。


       由于被多个流程访问的全局资源都应当使用 volatile限定符,所以可以得出结论,sig_atomic_t 类型的变量应该总是和volatile 限定符一起使用的。因为使用 volatile 限定符一起使用的。因为使用sig_atomic_t 类型的数据基本上都是被多个执行流程访问的全局变量。 


2.3 中断系统调用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值