【Linux】常见信号 + 进程和作业
文章目录
- 一、常见信号
- 引言
- 了解中断
- 1. 什么是信号?
- 查看所有信号:
- 2. 常见信号及其作用
- (1) **`SIGHUP` (1) - Hangup**
- (2) **`SIGINT` (2) - Interrupt**
- (3) **`SIGQUIT` (3) - Quit**
- (4) **`SIGKILL` (9) - Kill**
- (5) **`SIGTERM` (15) - Terminate**
- (6) **`SIGSTOP` (19) - Stop**
- (7) **`SIGCONT` (18) - Continue**
- (8) **`SIGSEGV` (11) - Segmentation Fault**
- (9) **`SIGPIPE` (13) - Broken Pipe**
- (10) **`SIGCHLD` (17) - Child Status Change**
- 3. 信号的处理方式
- 示例:捕获 `SIGINT`(`Ctrl+C`)
- 4. 如何发送信号?
- (1) 命令行工具:
- (2) 程序内发送:
- 5. 重要注意事项
- 6. 总结
- 二、进程和作业
- 1. 基本定义
- 进程(Process)
- 作业(Job)
- 2. 关键区别
- 3. 实际示例
- 进程示例
- 作业示例
- 4. 控制方式对比
- 进程控制
- 作业控制
- 5. 重要关系说明
- 6. 何时使用哪个概念?
一、常见信号
引言
在 Linux 系统中,信号(Signal)是一种进程间通信机制,用于通知进程发生了某种事件。信号可以由内核、其他进程或进程自身发送。理解这些信号的作用对于系统编程、进程管理和故障排查至关重要。本文将介绍 Linux 中最常见的信号及其用途。
了解中断
1. 什么是信号?
信号是 Linux 系统中一种异步通知机制,用于通知进程某个事件的发生。每个信号都有一个唯一的编号(如 SIGKILL
是 9
)和默认行为(如终止进程、忽略或暂停进程)。
查看所有信号:
kill -l
这将列出系统支持的所有信号(通常 1~31 是标准信号,34~64 是实时信号)。
2. 常见信号及其作用
(1) SIGHUP
(1) - Hangup
- 作用:终端断开或控制进程终止时发送。
- 默认行为:终止进程。
- 典型场景:
- 终端关闭时,该终端下的进程会收到
SIGHUP
。 nohup
命令可以让进程忽略SIGHUP
,避免被终止。
- 终端关闭时,该终端下的进程会收到
(2) SIGINT
(2) - Interrupt
- 作用:用户按下
Ctrl+C
时发送。 - 默认行为:终止进程。
- 典型场景:
- 用于交互式终止前台进程。
(3) SIGQUIT
(3) - Quit
- 作用:用户按下
Ctrl+\
时发送。 - 默认行为:终止进程并生成核心转储(core dump)。
- 典型场景:
- 用于强制终止进程并调试(生成 core 文件)。
(4) SIGKILL
(9) - Kill
- 作用:强制终止进程。
- 默认行为:立即终止进程,无法被捕获或忽略。
- 典型场景:
kill -9 PID
用于强制杀死无响应的进程。
(5) SIGTERM
(15) - Terminate
- 作用:请求进程正常终止。
- 默认行为:终止进程。
- 典型场景:
kill PID
默认发送SIGTERM
,允许进程清理资源后退出。
(6) SIGSTOP
(19) - Stop
- 作用:暂停进程执行。
- 默认行为:暂停进程,无法被捕获或忽略。
- 典型场景:
kill -19 PID
暂停进程,可用SIGCONT
恢复。
(7) SIGCONT
(18) - Continue
- 作用:恢复被暂停的进程。
- 默认行为:继续执行进程。
- 典型场景:
kill -18 PID
恢复被SIGSTOP
暂停的进程。
(8) SIGSEGV
(11) - Segmentation Fault
- 作用:进程访问非法内存时触发。
- 默认行为:终止进程并生成核心转储。
- 典型场景:
- 程序出现空指针解引用或越界访问时触发。
(9) SIGPIPE
(13) - Broken Pipe
- 作用:向无读端的管道写入数据时触发。
- 默认行为:终止进程。
- 典型场景:
echo "hello" | head -n1
,echo
会收到SIGPIPE
因为head
提前退出。
(10) SIGCHLD
(17) - Child Status Change
- 作用:子进程终止或暂停时发送给父进程。
- 默认行为:忽略。
- 典型场景:
- 父进程可通过
wait()
回收子进程资源,避免僵尸进程。
- 父进程可通过
3. 信号的处理方式
进程可以自定义信号处理函数(通过 signal()
或 sigaction()
),或选择:
- 默认行为(如终止、暂停、忽略)。
- 忽略信号(
SIGKILL
和SIGSTOP
除外)。 - 捕获信号(执行自定义处理函数)。
示例:捕获 SIGINT
(Ctrl+C
)
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void handler(int sig) {
printf("\nReceived SIGINT (Ctrl+C), but I won't die!\n");
}
int main() {
signal(SIGINT, handler); // 捕获 SIGINT
while (1) {
printf("Running...\n");
sleep(1);
}
return 0;
}
运行后,按 Ctrl+C
不会终止进程,而是执行自定义函数。
4. 如何发送信号?
(1) 命令行工具:
kill -SIGNAME PID
例如:kill -9 1234
(强制杀死 PID 1234)。pkill -SIGNAME process_name
例如:pkill -TERM nginx
(优雅终止 nginx)。
(2) 程序内发送:
kill()
系统调用:kill(pid, SIGTERM);
5. 重要注意事项
SIGKILL
和SIGSTOP
无法被捕获或忽略,用于强制控制进程。SIGTERM
是优雅终止的首选,允许进程清理资源。- 僵尸进程需要通过
SIGCHLD
处理或wait()
回收。 - 信号处理函数应尽量简单,避免调用非异步安全函数(如
printf
)。
6. 总结
信号 | 编号 | 默认行为 | 常见用途 |
---|---|---|---|
SIGHUP | 1 | 终止 | 终端断开时通知进程 |
SIGINT | 2 | 终止 | Ctrl+C 中断进程 |
SIGQUIT | 3 | 终止+core dump | Ctrl+\ 强制终止并调试 |
SIGKILL | 9 | 终止 | 强制杀死进程 |
SIGTERM | 15 | 终止 | 请求进程正常退出 |
SIGSTOP | 19 | 暂停 | 暂停进程(不可捕获) |
SIGCONT | 18 | 继续 | 恢复被暂停的进程 |
掌握这些信号有助于更好地管理 Linux 进程和编写健壮的程序。建议在实际开发中结合 man 7 signal
进一步学习!
二、进程和作业
在 Linux/Unix 系统中,"作业"和"进程"是两个密切相关但又有重要区别的概念。理解它们的差异对于系统管理和脚本编程至关重要。
1. 基本定义
进程(Process)
- 定义:进程是操作系统进行资源分配和调度的基本单位,是程序的一次执行实例。
- 特点:
- 有独立的地址空间
- 由内核直接管理
- 通过进程ID(PID)唯一标识
- 可以创建子进程(形成进程树)
作业(Job)
- 定义:作业是shell管理的概念,指用户通过shell启动的一个或多个关联进程的集合。
- 特点:
- 由shell维护和管理
- 可以包含一个进程或一个进程组(管道命令)
- 有作业号(Job ID)标识
- 可以控制为前台或后台运行
2. 关键区别
特性 | 进程 | 作业 |
---|---|---|
管理主体 | 操作系统内核管理 | Shell管理 |
标识符 | PID(进程ID) | 作业号(如%1) |
生命周期 | 独立存在 | 与Shell会话绑定 |
可见性 | 系统全局可见(通过ps命令) | 仅在当前Shell可见 |
控制方式 | 通过kill等系统调用 | 通过jobs、fg、bg等Shell内置命令 |
组成 | 单个执行实例 | 可以是一个进程或进程组 |
3. 实际示例
进程示例
$ sleep 100 &
[1] 25341 # 25341是PID,[1]是作业号
$ ps -ef | grep sleep
user 25341 12345 0 10:00 pts/0 00:00:00 sleep 100
作业示例
$ sleep 100 | sleep 200 & # 这是一个作业,包含两个进程
[1] 25341-25342
$ jobs
[1]+ Running sleep 100 | sleep 200 &
4. 控制方式对比
进程控制
# 查看进程
ps aux
# 终止进程
kill -9 PID
# 查看进程树
pstree
作业控制
# 查看作业
jobs
# 将后台作业调到前台
fg %1
# 将前台作业放到后台(先Ctrl+Z暂停,然后)
bg %1
# 终止作业
kill %1
5. 重要关系说明
- 一个作业可以包含多个进程(如管道命令
cmd1 | cmd2
) - Shell会话结束时,其管理的所有作业会收到SIGHUP信号(除非使用nohup或disown)
- 作业控制是Shell提供的功能,不同Shell(bash、zsh等)实现可能略有差异
- 进程是系统级概念,作业是用户级概念
6. 何时使用哪个概念?
- 当需要精细控制系统资源时,关注进程
- 当需要管理Shell中启动的任务时,使用作业控制
- 编写脚本时,通常需要同时考虑两者关系
理解这些区别可以帮助您:
- 更有效地管理系统资源
- 编写更健壮的Shell脚本
- 正确处理任务挂起、恢复和终止
- 避免产生僵尸进程或孤儿进程