1. 概念
信号(signal)是软件中断,是进程之间相互传递消息的一种方法,用于通知进程发生了事件,但是不能给进程传递任何数据。
2. 常用的信号类型
信号名 | 信号值 | 默认处理动作 | 发出信号的原因 |
---|---|---|---|
SIGHUP | 1 | A | 终端挂起或者控制进程终止 |
SIGINT | 2 | A | Ctrl+C |
SIGKILL | 9 | AEF | kill -9 signum 强制杀死程序 |
SIGALRM | 14 | A | 由alarm()函数发出信号 |
SIGTERM | 15 | A | kill 进程编号 或 killall 程序名通知程序 |
SIGUSR1 | 10 | A | 用户自定义信号1 |
SIGUSR2 | 12 | A | 用户自定义信号2 |
SIGCHLD | 17 | B | 子进程结束信号 |
- A: 终止进程
- B: 忽略此信号,将该信号丢弃,不做处理
- C: 终止进程并进行内核映像转储。
- D: 停止进程,进入停止状态的程序还能重新继续,一般用在调试的过程中
- E: 信号不能被捕获
- F: 信号不能被忽略
3. 信号的处理
进程对信号的处理方法有三种:
- 对该信号采用系统默认操作,大部分信号的默认操作是终止进程
- 设置中断的处理函数,收到信号后,由该函数处理
- 忽略某个信号,对该信号不做任何处理
signal函数可以设置对信号的处理方式
参数 sig表示信号的编号
参数func表示信号的处理方式,有三种情况:
- SIG_DFL: 恢复参数sig所指信号的默认处理方式
- SIG_IGN: 忽略参数sig所指的信号
- 一个自定义的处理信号的函数,信号的编号为这个自定义函数的参数
4. 信号的作用
- 在终止程序前,完成善后工作
- 想服务程序发送0的信号,可以检测程序是否存活
5. 代码示例
1. 忽略所有信号
#include <iostream>
#include <signal.h>
#include <unistd.h>
int main(){
for(int i = 1; i<=64;i++) {
signal(i, SIG_IGN);
}
for(;;){
sleep(1);
std::cout << "running..." << std::endl;
}
}
2. 为程序设置默认的信号处理函数
#include <iostream>
#include <signal.h>
#include <unistd.h>
void func(int sig){
std::cout << "收到信号:"<< sig << std::endl;
}
int main(){
// 为信号15 (SIGTERM) 设置自定义信号处理函数
signal(SIGTERM, func);
for(;;){
sleep(1);
std::cout << "running..." << std::endl;
}
}
6. 发送信号
Linux系统使用如下两个命令向程序发送信号
- kill -sig pid
- killall -sig 进程名
C语言提供了kill库函数
- int kill(pid_t pid, int sig)
kill函数参数:
1. pid > 0,将信号传递给进程号为pid的进程
2. pid = 0, 将信号传给相同进程组的所有进程,常用于父进程给子进程发送信号,发送信号者也会收到自己发出的信号。
3. pid = -1, 将信号广播给系统内所有的进程。
kill函数返回值:
成功执行时,返回0,失败返回-1,errno被设为以下的某个值
- EINVAL: 指定的信号码无效,参数sig不合法
- EPERM: 权限不够,无法传送信号给指定进程
- ESRCH: 参数pid所指定的进程或进程组不存在