三十、Linux 进程与信号——信号的概念及 signal 函数
30.1 信号的基本概念
- 信号(signal)机制是Linux 系统中最为古老的进程之间的通信机制,解决进程在正常运行过程中被中断的问题,导致进程的处理流程会发生变化
- 信号是软件中断
- 信号是异步事件
- 不可预见
- 信号有自己的名称和编号
- 信号和异常处理机制
- 信号发生的来源
- 硬件来源:如按下键盘或其他硬件故障,信号是由驱动程序产生
- 软件来源:最常用发送信号的系统函数是 kill(),raise(),alarm() 和 setitimer() 等函数,软件来源还包括一些非法运算等操作,软件设置条件(如:gdb调试),信号是由内核产生。
查看系统当中的信号:kill -l
- [1 ~ 31] 信号称为非实时信号
- 发送的信号可能丢失,不支持信号排队
- [32 ~ 64] 信号称为实时信号
- 发送的多个实时信号都会被接受,支持信号排队
- 信号无优先 信号定义的地方:/usr/include/bits/signum.h 和 signum-generic.h
30.2 信号的处理和变革
30.2.1 信号的处理
- 忽略信号
- SIGKILL 和 SIGSTOP 永远不能忽略
- 忽略硬件异常
- 进程启动时 SIGUSR1 和 SIGUSR2 两个信号被忽略
- 执行默认操作
- 每个信号有默认动作,大部分信号默认动作是终止进程
- 捕获信号
- 告诉内核出现信号时调用自己的处理函数
- SIGKILL 和 SIGSTOP 不能被捕获
30.2.2 信号变革
- 信号出现在早期的 UNIX 中
- 早期信号模型是不可靠的
- BSD 和 SYSTEM V 分别对早期信号进行扩展,但是相互不兼容
- POSIX 统一了上述两种模型,提供了可靠信号模型
30.3 signal 函数
1 #include <signal.h> 2 void (*signal(int signo, void (*func)(int )))(int );
- 函数功能:向内核登记信号处理函数
- 函数参数:
- signo:要登记的信号值
- func:
- 信号处理函数指针
- SIG_IGN:忽略信号
- SIG_DFL:采用系统默认的方式处理信号,执行默认操作
- 返回值:若成功,则返回先前的信号处理函数指针,出错,则返回 SIG_ERR
signal 函数原型如下:
1 #include <signal.h> 2 #include <stdlib.h> 3 #include <stdio.h> 4 #include <unistd.h> 5 6 /** 定义信号处理函数 7 * signo 进程捕获到的信号 8 */ 9 void sig_handler(int signo) 10 { 11 printf("%d, %d occured\n", getpid(), signo); 12 } 13 14 int main(void) 15 { 16 /** 向内核登记信号处理函数以及信号值 */ 17 if(signal(SIGTSTP, sig_handler) == SIG_ERR) { 18 perror("signal sigtstp error"); 19 } 20 21 if(signal(SIGINT, sig_handler) == SIG_ERR) { 22 perror("signal sigint error"); 23 } 24 25 if(signal(SIGUSR1, sig_handler) == SIG_ERR) { 26 perror("signal usr1 error"); 27 } 28 29 if(signal(SIGUSR2, sig_handler) == SIG_ERR) { 30 perror("signal usr2 error"); 31 } 32 33 if(signal(SIGKILL, SIG_IGN) == SIG_ERR) { 34 perror("signal sigtstp error"); 35 } 36 37 if(signal(SIGSTOP, SIG_IGN) == SIG_ERR) { 38 perror("signal sigint error"); 39 } 40 int i = 0; 41 while(i < 30) { 42 printf("%d out %d\n", getpid(), i++); 43 sleep(50); 44 } 45 46 return 0; 47 }