信号(Signal)是Linux系统中用于进程之间相互通信或操作的一种机制。信号是一个相当广泛的课题;在这里,我们仅仅探讨几种最重要的信号以及利用信号控制进程的技术。
        信号是一个发送到进程的特殊信息。信号机制是异步的;当一个进程接收到一个信号时,它会立刻处理这个信号,而不会等待当前函数甚至当前一行代码结束运行。信号有几十种,分别代表着不同的意义。信号之间依靠它们的值来区分,但是通常在程序中使用信号的名字来表示一个信号。在Linux系统中,这些信号和以它们的名称命名的常量均定义在/usr/include/bits/signum.h文件中。(通常程序中不需要直接包含这个头文件,而应该包含<signal.h>。)
        当一个进程接收到信号,基于不同的处理方式(disposition),该进程可能执行几种不同操作中的一种。每个信号都有一个默认处理方式(default disposition),当进程没有指定自己对于某个信号的处理方式的时候,默认处理方式将被用于对对应信号作出响应。对于多数种类的信号,程序都可以自由指定一个处理方式——程序可以选择忽略这个信号,或者调用一个特定的信号处理函数。如果指定了一个信号处理函数,当前程序会暂停当前的执行过程,同时开始执行信号处理函数,并且当信号处理函数返回之后再从被暂停处继续执行。
        Linux系统在运行中出现特殊状况的时候也会向进程发送信号通知。例如,当一个进程执行非法操作的时候可能会收到SIGBUS(主线错误),SIGSEGV(段溢出错误)及SIGFPE(浮点异常)这些信号。这些信号的默认处理方式都是终止程序并且产生一个核心转储文件(core file)。
一个进程除了响应系统发来的信号,还可以向其它进程发送信号。对于这种机制的一个最常见的应用就是通过发送SIGTERM或SIGKILL信号来结束其它进程。3#3 除此之外,它还常见于向运行中的进程发送命令。两个“用户自定义”的信号SIGUSR1和SIGUSR2就是专门作此用途的。SIGHUP信号有时也用于这个目的——通常用于唤醒一个处于等待状态的进程或者使进程重新读取配置文件。
系统调用sigaction用于指定信号的处理方式。函数的第一个参数是信号的值。之后两个参数是两个指向sigaction结构的指针;第一个指向了将被设置的处理方式,第二个用于保存先前的处理方式。这两个sigaction结构中最重要的都是sa_handler域。它可以是下面三个值:

· SIG_DFL,指定默认的信号处理方式
· SIG_IGN,指定该信号将被忽略
· 一个指向信号处理函数的指针。这个函数应该接受信号值作为唯一参数,且没有返回值。



        因为信号处理是异步进行的,当信号处理函数被调用的时候,主程序可能处在非常脆弱的状态,并且这个状态会一直保持到信号处理函数结束。因此,应该尽量避免在信号处理函数中使用输入输出功能、绝大多数库函数和系统调用。
        信号处理函数应该做尽可能少的工作以响应信号的到达,然后返回到主程序中继续运行(或者结束进程)。多数情况下,所进行的工作只是记录信号的到达。而主程序则定期检查是否有信号到达,并且针对当时情况作出相应的处理。
       信号处理函数也可能被其它信号的到达所打断。虽然这种情况听起来非常罕见,一旦出现,程序将非常难以确定问题并进行调试。甚至于对全局变量赋值可能也是不安全的,因为一个赋值操作可能由两个或更多机器指令完成,而在这些指令执行期间可能会有第二个信号到达,致使被修改的全局变量处于不完整的状态。如果你需要从信号处理函数中设置全局标志以记录信号的到达,这个标志必须是特殊类型sig_atomic_t的实例。Linux保证对于这个类型变量的赋值操作只需要一条机器指令,因此不用担心可能在中途被打断。在Linux系统中,sig_atomic_t就是基本的int类型;事实上,对int或者更小的整型变量以及指针赋值的操作都是原子操作。不过,如果你希望所写的程序可以向任何标准UNIX系统移植,则应将所有全局变量设为sig_atomic_t类型。
        如下所示,代码列表3.5中的简单程序中,我们利用信号处理函数统计程序在运行期接收到SIGUSR1信号的次数。SIGUSR1信号是一个为应用程序保留的信号。
        代码列表 3.5 (sigusr1.c)使用信号处理函数

#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
sig_atomic_t sigusr1_count = 0;
void handler(int signal_number)
{
	++sigusr1_count;
}
int main ()
{
	struct sigaction sa;
	memset (&sa, 0, sizeof (sa));
	sa.sa_handler = &handler;
	sigaction (SIGUSR1, &sa, NULL);
	/* 这里可以执行一些长时间的工作。*/
	sleep(20);
	printf ("SIGUSR1 was raised %d times\n", sigusr1_count);
	return 0;
}


GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐