【Linux】进程信号(上)

[复制链接]
发表于 2026-10-5 20:21:32 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

你按下 Ctrl+C,前台进程就退了。这个动作在操作系统里不是"你关掉了程序",而是一条信号从内核发到了进程。信号机制贯穿 Linux:它既用来通知异常,也用来做进程间通信和线程同步。这篇从生活里的红绿灯讲起,把信号概念、三种处理方式、Ctrl+C 对应的 2 号信号、kill -l 与 man 7 signal 的用法,以及 signal 函数怎么改自己的处理方式,串成一条完整链路。

一、信号是什么

1.1 生活中的信号

日常里有电话铃、红绿灯、闹钟,它们存在的意义是提示某种信息。外卖员到了给你发个"信号",你知道该下楼取餐;但你也许正在开会脱不开身,过一会儿才去拿——这说明收到了信号,也可以选择不同的处理方式。

通过长期教导,我们能识别某种信号的作用以及该怎么处理它:绿灯通行、闹钟响起床,这些叫默认处理动作。同时我们还能自定义处理方式,比如闹钟响了继续睡。

归纳一下,接收信号后有三种处理方式:

  • 执行默认动作;
  • 执行自定义动作(信号处理函数);
  • 忽略信号。

1.2 进程中的信号

上面这套在进程里同样成立,进程必须能识别并用某种方式处理不同的信号。

在 shell 里启动一个前台进程然后按 Ctrl+C,进程直接退出。原理是:按下 Ctrl+C 后,键盘产生的硬件中断被操作系统获取,操作系统把你的操作解释成信号发送给前台进程,进程收到该信号后执行退出动作。

信号相对于进程的运行流程是异步的——前台进程运行中,用户随时可能按下 Ctrl+C,进程根本等不到"准备好"的时刻。

1.3 信号的概念与查看

进程信号是 Linux 中用于进程间通讯和控制的一种机制,是进程之间异步通知事件的一种方式,属于软中断。典型应用:进程间通信、异常处理、线程同步。

信号有很多种,用 kill -l 命令查看:

kill -l

上面按下的 Ctrl+C,本质上被解释成了2 号信号 SIGINT,被进程接收。

其中 1 到 31 号是普通信号,34 号往后是实时信号。每种信号在什么情况下产生、默认处理动作是什么,通过 man 7 signal 查:

man 7 signal

二、用 signal 函数改处理方式

可以用 signal 函数修改进程对某个信号的处理动作,原型:

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);

其中 handler 就是用户自定义的信号处理动作。用法示例:

void myhandler(int sig)
{
    // 自定义处理逻辑
}

int main()
{
    signal(SIGINT, myhandler);   // 把 2 号信号的处理换成自己的函数
    while (1) {
        sleep(1);
    }
    return 0;
}

这样按 Ctrl+C 就不会直接退出,而是走进 myhandler。注意三条工程经验:

  • 信号处理函数里只做极短的事(写日志日志、置标志位),不要在里面做耗时操作;
  • 不是所有信号都能自定义,SIGKILL 和 SIGSTOP 无法被捕获或修改;
  • 处理函数中可用的函数是受限的,涉及异步安全,别随手 printf 一堆东西。

三、信号的三种产生途径

2.1 组合键产生

最典型就是 Ctrl+C(2 号 SIGINT)。同理 Ctrl+\ 对应 SIGQUIT,用于请求进程退出并通常产生核心转储。

2.2 函数发送信号

  • kill 命令:kill -信号号 进程PID,或 kill -信号名 PID。看到"进程停不下来"时,kill -2 PID 与 kill -9 PID 是最常用的两条。
  • kill 函数:给指定进程发信号,参数是 pid 与信号值。
  • raise 函数:给当前进程自己发信号,常用于自检失败后主动自杀。
  • abort 函数:当前进程异常终止,通常伴随核心转储。

2.3 CoreDump:为什么进程崩了要看文件

进程收到可导致终止的信号而退出时,系统可以把进程用户空间的内存映像保存到磁盘,这就是核心转储(core dump)。默认常被关掉,需要时打开:

ulimit -c unlimited

有了 core 文件,配合 gdb 就能还原崩溃时的调用栈,定位野指针、越界这类问题:

gdb ./myexe core

2.4 特定软件条件下产生

除上面三种,还有一类来自内核的事件通知:比如子进程退出时给父进程发 17 号 SIGCHLD,越界访问产生的段错误对应 11 号 SIGSEGV,除零对应 8 号 SIGFPE。这些在 man 7 signal 里都能查到触发条件。

四、把信号排进实战

排障时可以按这个顺序想:先 kill -l 确认信号编号,再 man 7 signal 看默认动作,然后判断该走默认(比如 SIGKILL 强杀)还是装自己的 handler(比如 SIGTERM 优雅退出)。写服务时更习惯用 signal 或 sigaction 装一个 SIGTERM 处理函数,在里面做"停止接收新请求—处理完手上任务—退出",这正是优雅停止的实现基础。

qidao123.com企服评测-应用市场 编辑提示

本文按信号的生活类比与三种处理方式(默认/自定义/忽略)、前台进程与 Ctrl+C 的硬件中断转信号过程与异步特性、kill -l 查看信号与 1-31 普通信号与 34+ 实时信号的划分、man 7 signal 查默认动作、signal 函数原型与自定义 handler 写法与三条工程约束、kill 命令与 kill/raise/abort 三个函数、CoreDump 的 ulimit -c 打开与 gdb 分析、以及 SIGCHLD 与 SIGSEGV 等内核侧触发场景,重排成"概念—产生—捕获—分析"的信号入门链。文中函数名与信号编号取自 POSIX 与 Linux 信号手册,示例代码为教学示意;信号相关操作请在自有或已授权进程与环境中验证,强杀信号可能导致未保存数据丢失,生产环境建议先发 SIGTERM 等待优雅退出。

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表