一、Linux信号
信号是什么?就是信息运载的工具,是消息的载体。在Linux系统中,Signal就是信号的一种表现形式,但它是一种非常简单的处理机制,只能处理信号编号这种简单的数据内容。需要引起开发者注意的是,信号与信号量不是一回事。后者是用于PV原语一类中的一个标记,不过从本质上看,其仍然是一个东西。
在日常生活中,信号的表现有很多,门铃、起床号、钟声以及人们的叫喊声等等。所以开发者很容易的理解,信号是一种异步通知机制,它告诉应用进程,某种指定的事件发生了,进程可以根据情况捕获并处理这些信号。指定,意味着开发者已经提前准备了对这种事件的处理机制(忽略和不处理也是一种准备好),而且信号是被动接受的,它可能被忽略、延缓等处理。而且,正如刚刚所说,信号的种类非常之多。
在Linux系统中,不同的情况下可以划分不同的信号种类。一般有两种划分方式:
- 早期的Unix中划分可靠信号和不可靠信号
信号值1~31为不可靠信号,但需去除SIGKILL和SIGSTOP信号,其它为可靠信号。不可靠信号使用signal()处理而可靠信号使用sigaction()函数进行处理 - POSIX标准定义划分为普通信号和实时信号
实时信号定义为SIGRTMIN-SIGRTMAX,信号编号一般是34-64,其它为普通信号。实时信号可以看作可靠信号的一个子集,它通过sigaction()函数进行处理
不可靠信号不支持排队也不支持携带除信号编号之外的数据,它有丢失的可能。可靠信号支持排除队处理可携带少量的数据,不会丢失。而实时信号则既支持排队处理又可携带数据并且可对信号进行优先级处理,信号也不会丢失。
在现代的Linux系统中,即使不可靠的信号基本也进行了可靠性的处理,所以在一些不是特别严格需要处理的条件下,可以忽略对信号丢失的处理控制。
二、信号的产生
在Linux系统中,常见的信号产生的场景有如下几种:
- IO产生信号
这里最典型的就是键盘。在Linux系统中,大家可以使用ctrl+c,ctrl+z等来处理进程,就是因为它们向目标进程发送了信号 - 系统调用
这是终端命令中经常使用的一种方式,通过命令向指定进程发送相关的信号,最典型的就是kill命令,向指定进程发送kill命令,会杀死指定的进程 - 软件产生信号
软件产生信号是系统中的一些应用或者开发者自己编写的信号发生进程,发送了相关的信号。常见的如定时器信号,这个就用得非常多了 - 硬件产生信号
这种其实开发者更常遇到,只是不过可能不注意罢了。比如程序进入调试状态或直接Crash,都会由系统发送信号,比如Crash有可能发送的就是经典的SIGSEGV段错误信号
三、信号的运行机制和原理
在Linux系统中,在通过上述的机制产生信号后,信号会发送到指定进程中,进程为了处理异步的信号,则需要将其进行保存到状态队列中。而根据不同的信号,保存的机制又有不同。普通信号在被处理之前到达多次,进程对其只保存一次;而对实时信号则要保存到一个专有的队列中,从而保证信号处理的可靠性。下面对其进行分析说明:
- 信号直接处理即信号抵达即Delivery
- 信号产生但未抵达,其状态称为信号未决即pending
- 进程阻塞指定信号即block,则称为屏蔽信号
- 被阻塞的信号保持未决状态直到进程解除阻塞并执行抵达动作
- 要区分忽略和阻塞的不同。忽略是信号抵达状态下的执行方式
在进程的PCB中,对上述的状态都有相关的位图保存,开发者可以通过sigset_t、sigprocmask和sigpending等接口处理当前的信号状态。在内核中,一般在下列情况会检查相关的信号:
- 系统调用返回
- 中断处理完成
- 进程从睡眠状态唤醒
进程在检测到相关的信号后,就会进行相关的处理操作(也就是Delivery)。
四、信号的处理
在信号的处理流程中,如果信号发现被阻塞,则保持待处理的状态。否则其处理主要分为以下几种情况:
- 默认动作处理
这是最常见的情况,即信号使用默认的处理机制(其实就是系统自定义的处理方法) - 自定义动作处理
开发者如果定义了处理的相关方法,则会直接调用此方法 - 忽略处理
如果发现信号被忽略,则直接抛弃此信号,不再处理
需要说明的是term和Core信号,前者是终止进程;后者是终止进程并形成一个Core文件。后者的Core文件为进程的退出(特别是异常退出)提供了调试的相关内容。
五、信号的特点
通过上面的分析,可以总结出Linux系统中的信号有以下几个特点:
- 异步实现
信号在整体的处理环节中,是不能为上层应用控制的,它可以随时触发动作 - 简单性
信号只能处理一些简单内容(信号编号)而无法处理较多的数据 - 不可靠
标准信号因为各种情况的处理可能导致丢失,但实时信号不会 - 内核中转
信号机制必须通过内核传递和处理 - 处理方式灵活
Linux系统中的信号处理机制提供了多种处理方式,包括忽略处理、默认处理、自定义处理
信号的例程都比较简单,所以本文就不再给出相关的例程了,如果想针对例程进行对比学习分析,可查看前面的"信号应用"相关或直接在网上查阅相关资料即可。
六、总结
在前面已经总结分析了信号的应用,随着在Linux中开发应用的深入,就有必要了解一下Linux系统中信号的运行机制和原理。正所谓知己知彼,百战百胜。技术的应用和学习就是这么一个由浅到深,由表及里的不断深入的过程。与诸君共勉!