当前位置: 首页 > java >正文

linux 进程信号

目录

1.什么是信号

2.信号的产生

2.1 捕获信号的周边函数介绍

 2.1.1 signal 捕获信号处理函数

 2.1.2 sigaction更强大的捕获信号处理函数

 2.1.3 sigemptyset(), sigaddset(),sigfillset() 等函数操作阻塞信号集block(阻塞)表

2.2 信号的产生方式

2.2.1 外设发送(如键盘)

2.2.2 进程发送信号

 2.2.3 硬件信号

2.2.4 软件信号

3.信号的保存

4.信号的处理

4.1 什么时候处理这个信号呢

5.信号的周边问题

5.1用户态和内核态

5.1.1 操作系统是如何运行的

5.2 core dump(核心储存)

5.3 实时信号和标准信号


1.什么是信号

信号在人身体层面来讲,是一种“警示”,比如长时间未进食,“饥饿”就是一种信号。生活层面来讲,快递,外卖的到达,也是一种信号。那对于计算机来说,什么是信号呢。

硬件层面来讲,分为数字信号和模拟信号

  • 数字信号

    • 用离散的高电平(1)低电平(0)表示信息,是计算机内部处理的基础。

    • 例如:CPU通过电信号传输二进制指令,USB接口传输数字数据。

  • 模拟信号

    • 连续变化的物理量(如电压、电流),需通过ADC(模数转换器)转换为数字信号供计算机处理。

    • 例如:麦克风捕获的声波、传感器采集的温度数据

软件层面来讲,就是OS给进程发送,异步通知的一种机制。通过kill -l 可查看。

 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX	

/* ISO C99 signals.  */

#define  SIGINT      2  /* Interactive attention signal.  */

#define  SIGILL      4  /* Illegal instruction.  */

#define  SIGABRT     6  /* Abnormal termination.  */

#define  SIGFPE      8  /* Erroneous arithmetic operation.  */

#define  SIGSEGV     11 /* Invalid access to storage.  */

#define  SIGTERM     15 /* Termination request.  */

/* Historical signals specified by POSIX. */

#define  SIGHUP      1  /* Hangup.  */

#define  SIGQUIT     3  /* Quit.  */

#define  SIGTRAP     5  /* Trace/breakpoint trap.  */

#define  SIGKILL     9  /* Killed.  */

#define SIGBUS    10 /* Bus error.  */

#define  SIGSYS      12 /* Bad system call.  */

#define  SIGPIPE     13 /* Broken pipe.  */

#define  SIGALRM     14 /* Alarm clock.  */

/* New(er) POSIX signals (1003.1-2008, 1003.1-2013).  */

#define  SIGURG      16 /* Urgent data is available at a socket.  */

#define  SIGSTOP     17 /* Stop, unblockable.  */

#define  SIGTSTP     18 /* Keyboard stop.  */

#define  SIGCONT     19 /* Continue.  */

#define  SIGCHLD     20 /* Child terminated or stopped.  */

#define  SIGTTIN     21 /* Background read from control terminal.  */

#define  SIGTTOU     22 /* Background write to control terminal.  */

#define  SIGPOLL     23 /* Pollable event occurred (System V).  */

#define  SIGXCPU     24 /* CPU time limit exceeded.  */

#define  SIGXFSZ     25 /* File size limit exceeded.  */

#define  SIGVTALRM   26 /* Virtual timer expired.  */

#define  SIGPROF     27 /* Profiling timer expired.  */

#define  SIGUSR1     30 /* User-defined signal 1.  */

#define  SIGUSR2     31 /* User-defined signal 2.  */

/* Nonstandard signals found in all modern POSIX systems

   (including both BSD and Linux).  */

#define  SIGWINCH 28 /* Window size change (4.3 BSD, Sun).  */

/* Archaic names for compatibility.  */

#define  SIGIO    SIGPOLL  /* I/O now possible (4.2 BSD).  */

#define  SIGIOT      SIGABRT  /* IOT instruction, abort() on a PDP-11.  */

#define  SIGCLD      SIGCHLD  /* Old System V name */

/* Not all systems support real-time signals.  bits/signum.h indicates

   that they are supported by overriding __SIGRTMAX to a value greater

   than __SIGRTMIN.  These constants give the kernel-level hard limits,

   but some real-time signals may be used internally by glibc.  Do not

   use these constants in application code; use SIGRTMIN and SIGRTMAX

   (defined in signal.h) instead.  */

#define __SIGRTMIN   32

#define __SIGRTMAX   __SIGRTMIN

/* Biggest signal number + 1 (including real-time signals).  */

#define _NSIG     (__SIGRTMAX + 1)

2.信号的产生

2.1 捕获信号的周边函数介绍

来源例子
用户输入按下 Ctrl+C 触发 SIGINTCtrl+\ 触发 SIGQUIT
内核检测到异常段错误(SIGSEGV)、除零错误(SIGFPE)。
其他进程通过 kill() 系统调用发送信号(如 SIGTERM 终止进程)。
操作系统事件子进程退出时向父进程发送 SIGCHLD,终端断开连接发送 SIGHUP

如何验证这些信号的来源呢,以Ctrl+C 触发 SIGINT为例

在这里我们需要介绍两种信号捕捉函数

 2.1.1 signal 捕获信号处理函数

extern __sighandler_t signal (int __sig, __sighandler_t __handler)

/*
返回值:
     成功:返回传入的信号处理函数
     失败:返回((__sighandler_t)-1)
参数:
     __sig 捕获的信号
     __handler 处理信号的方法 函数指针,声明如下
*/
/* Type of a signal handler.  */
typedef void (*__sighandler_t) (int);

 2.1.2 sigaction更强大的捕获信号处理函数

/* Get and/or set the action for signal SIG.  */
extern int sigaction (int __sig, const struct sigaction *__restrict __act,
              struct sigaction *__restrict __oact) __THROW;
/*
返回值:
      成功:返回 0
      失败:返回 -1 并设置 errno
参数:
      __sig 捕获的信号(如 SIGINT, SIGTERM 等)
      __act 结构体,需要处理的新动作
      __oact 结构体,保留之前的处理动作
*/

struct sigaction *__restrict 结构体说明

struct sigaction
  {
    /* 
        Signal handler. 信号处理函数 
        sa_handler:
        简单的信号处理函数,类似于 signal() 的处理方式
        也可以是 SIG_DFL(默认)或 SIG_IGN(忽略)
        sa_sigaction:
        更复杂的信号处理函数,当 sa_flags 包含 SA_SIGINFO 时使用
        接收三个参数:
        int sig:信号编号
        siginfo_t *info:包含信号的详细信息
        void *ucontext:上下文信息(CPU状态等)
    */
#if defined __USE_POSIX199309 || defined __USE_XOPEN_EXTENDED
    union
      {
    /* Used if SA_SIGINFO is not set.  */
    __sighandler_t sa_handler;
    /* Used if SA_SIGINFO is set.  */
    void (*sa_sigaction) (int, siginfo_t *, void *);
      }
    __sigaction_handler;
# define sa_handler    __sigaction_handler.sa_handler
# define sa_sigaction    __sigaction_handler.sa_sigaction
#else
    __sighandler_t sa_handler;
#endif

    /*

        Additional set of signals to be blocked.

        指定处理信号时,要阻塞的信号集(block

     */
    __sigset_t sa_mask; 

    /*

        Special flags

        修改信号行为的标志

  • 控制信号行为的标志,常用值:

    • SA_SIGINFO:使用 sa_sigaction 而非 sa_handler

    • SA_RESTART:自动重启被信号中断的系统调用

    • SA_NODEFER:在处理信号时不自动阻塞该信号

    • SA_RESETHAND:处理信号后重置为默认动作

.  */
    int sa_flags;

    /*

        Restore handler.  

        已废弃

    */
    void (*sa_restorer) (void);
  };

注:

  • sa_mask:

    • 指定在处理当前信号时要阻塞的其他信号集

    • 使用 sigemptyset()sigaddset(),sigfillset() 等函数操作

 2.1.3 sigemptyset()sigaddset(),sigfillset() 等函数操作阻塞信号集block(阻塞)表

sigemptyset 初始化一个空的信号集(不包含任何信号) 

/*

         Clear all signals from SET.

参数

  • set: 指向要初始化的信号集的指针

返回值

  • 成功: 返回 0

  • 失败: 返回 -1 并设置 errno

*/

extern int sigemptyset (sigset_t *__set) __THROW __nonnull ((1));

sigfillset 初始化一个包含所有信号的信号集

/*

        Set all signals in SET.  

        

参数

  • set: 指向要初始化的信号集的指针

返回值

  • 成功: 返回 0

  • 失败: 返回 -1 并设置 errno

*/

extern int sigfillset (sigset_t *__set) __THROW __nonnull ((1));

sigaddset 向信号集中添加一个指定的信号

/*

        Add SIGNO to SET.  

参数

  • set: 指向信号集的指针

  • signum: 要添加的信号编号(如 SIGINT, SIGTERM 等)

返回值

  • 成功: 返回 0

  • 失败: 返回 -1 并设置 errno

*/

extern int sigaddset (sigset_t *__set, int __signo) __THROW __nonnull ((1));

sigdelset  从信号集中删除一个指定的信号

/*

        Remove SIGNO from SET.

        

参数

  • set: 指向信号集的指针

  • signum: 要删除的信号编号

返回值

  • 成功: 返回 0

  • 失败: 返回 -1 并设置 errno

 */

extern int sigdelset (sigset_t *__set, int __signo) __THROW __nonnull ((1));

sigismember 测试一个信号是否在信号集中

/*

        Return 1 if SIGNO is in SET, 0 if not.

参数

  • set: 指向信号集的指针

  • signum: 要测试的信号编号

返回值

  • 信号在集合中: 返回 1

  • 信号不在集合中: 返回 0

  • 出错: 返回 -1 并设置 errno

 */

extern int sigismember (const sigset_t *__set, int __signo)

注:标准信号(Standard Signals)(1-31)中SIGKILL,SIGSTOP是无法被捕获的 

2.2 信号的产生方式

2.2.1 外设发送(如键盘)

Ctrl+C(前台进程才能收到) 触发 SIGINT(信号)为例 

#include <unistd.h>
#include <signal.h>
void sigcb(int signal)
{cout << "signal: " << signal << endl;
}int main()
{signal(SIGINT, sigcb);for(;;);
}

打印结果,是可以收到2号(SIGINT)信号。

注:打开XShell连接服务器,打开一组会话(session)时,会自主启动一个bash进程对我们的命令行进行解析,此时bush进程为前台进程,以"./.exe"方式去执行我们的程序时,会将该进程替换为后台进程。再使用Ctrl+C是杀不掉该进程(前台进程)的,可以通过kill命令+进程id 去杀掉前台进程

jobs 命令: 查看当前 Shell 会话中的后台任务
fg 任务号 :特定进程,提到前台
ctrl + Z :切换到后台
bg 任务号:后台进程回复运行

2.2.2 进程发送信号
kill()是 Linux/Unix 系统中用于向进程发送信号的系统调用接口。
#include <sys/types.h>
#include <signal.h>int kill(pid_t pid, int sig);

返回值:

0成功发送信号
-1发送失败,错误码存储在 errno 中
参数:
pid:进程号(普通用户只能给当前进程发送信号,超级用户(root)不受限制)
sig:发送的信号
#include <stdlib.h>
void abort(void);
标准 C 库函数,用于 异常终止当前进程,并生成核心转储文件(core dump)用于调试。

参数

  • 无参数:abort() 不接受任何参数

返回值

  • 无返回值:该函数不会返回到调用者

     

  • 信号发送

    • 首先向当前进程发送 SIGABRT 信号(信号编号 6)

    • 如果程序没有捕获 SIGABRT,则进程会立即终止

  • 信号处理

    • 如果程序设置了 SIGABRT 的信号处理函数:

      • 会先执行信号处理函数

      • 如果信号处理函数返回(没有退出进程),abort() 仍会终止进程

  • 终止行为

    • 进程异常终止

    • 可能生成核心转储文件(取决于系统设置)

    • 返回终止状态 134(128 + SIGABRT 信号编号 6)

 2.2.3 硬件信号

OS如何知道硬件异常?当程序中存在,如除零错误,野指针的使用等让程序崩溃的问题时,OS会发送信号,终止进程。它是如何得知这些异常的?

首先我们要了解,信号是OS发送的,OS作为软硬件的管理者,是可以知道寄存器报错的,生产厂家在CPU内置的异常检测机制。

处理器生产时确实内置了硬件异常检测电路:

  • 算术逻辑单元(ALU):检测除零、溢出等算术异常

  • 内存管理单元(MMU):检测非法内存访问

  • 指令解码器:检测非法指令码

 以非法访问地址为例:

2.2.4 软件信号

alarm() 是 POSIX 标准中的系统调用,用于设置一个定时器,在指定的时间后向进程发送 SIGALRM 信号。

extern unsigned int alarm (unsigned int __seconds) __THROW;
 

参数说明

参数类型说明
secondsunsigned int定时器的时间(秒),如果为0则表示取消已设置的定时器

返回值

返回值说明
0之前没有设置过定时器
>0之前设置的定时器剩余时间(秒)

SIGPIPE(管道错误)

管道读端关闭,写端不能写,否则会发出 SIGPIPE 信号,即会生成 BROKEN PIPE 错误

3.信号的保存

信号可以产生,那我们是不是需要将这些信号保存,等待后续处理,那么在创建进程控制块的时候就有必要信号已经处理方式保存。

1.实际执行信号的处理动作称为信号递达(Delivery)
2.信号从产生到递达之间的状态,称为信号未决(Pending)
3.进程可以选择阻塞 (Block )某个信号。
4.被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作.
注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。

4.信号的处理

信号的产生我们已经知道了,处理方式我们也了解了。那么,

4.1 什么时候处理这个信号呢

进程从内核态转回到用户态的时候,处理信号。

注:当进程启动,被调度,就会不断从内核切换到用户,用户切换到内核

5.信号的周边问题

5.1用户态和内核态

5.1.1 操作系统是如何运行的

1. 用户态(User Mode)

  • 应用程序运行的特权级别

  • 受限的指令集和资源访问权限

  • 不能直接访问硬件或内存管理单元(MMU)等关键资源

2. 内核态(Kernel Mode)

  • 操作系统内核运行的特权级别

  • 完全的系统控制权

  • 可以执行所有CPU指令,访问所有硬件资源

调用open(),打开磁盘文件为例:

 操作系统就是通过硬件时钟的中断(以特定且固定的频率向CUP发送中断)进行调度。当无中断到来时,操作系统不做任何处理。通过syscall 可以让CPU自助触发一次中断请求

调用指令syscall

寄存器使用

  • eax:系统调用号

  • ebx:第一个参数

  • ecx:第二个参数

  • edx:第三个参数

  • esi:第四个参数

  • edi:第五个参数

  • ebp:第六个参数

返回值:通过rax返回

示例:

mov eax, 4    ; write的系统调用号
mov ebx, 1    ; 文件描述符
mov ecx, msg  ; 缓冲区地址
mov edx, len  ; 长度
int 0x80

注:信号实际就是模仿硬件中断 

5.2 core dump(核心储存)

core dump是用于生成出错文件,定位具体问题(gdp core_file),上述介绍了一个函数abort,终止进程时会生成core dump,但是当我们调用的时候,是没有生成的,那是因为一般都是关闭的,为什么要关闭?

  1. 安全考虑

    • Core dump 包含程序崩溃时的内存映像,可能包含敏感信息(如密码、密钥等)

    • 可能被攻击者利用来分析系统漏洞

  2. 资源管理

    • Core dump 文件可能非常大,占用大量磁盘空间

    • 频繁崩溃可能导致磁盘空间被迅速耗尽

  3. 隐私保护

    • 防止用户数据通过 core dump 意外泄露

  4. 性能考虑

    • 生成 core dump 会消耗系统资源,可能影响系统性能

5.3 实时信号和标准信号

1. 标准信号(1-31)

特点

  1. 非可靠信号(不可靠信号)

    • 如果同一个信号在阻塞期间多次触发,最终只会递送一次(会丢失中间的信号)。

    • 例如:连续按多次 Ctrl+CSIGINT),进程可能只收到一次。

  2. 无优先级顺序

    • 如果多个标准信号同时处于未决状态,它们的处理顺序是不确定的

  3. 无附加信息

    • 信号处理函数 void handler(int sig) 只能接收信号编号,无法获取发送者 PID 等额外信息。

  4. 部分信号行为固定

    • SIGKILL(9)和 SIGSTOP(19)不能被捕获、阻塞或忽略,只能由内核处理。

常见标准信号

信号编号信号名默认行为触发场景
1SIGHUP终止进程终端挂断(如 SSH 断开)
2SIGINT终止进程Ctrl+C 中断
9SIGKILL强制终止kill -9 PID
15SIGTERM终止进程默认的 kill 命令信号
17SIGCHLD忽略子进程状态改变(退出/暂停)

2. 实时信号(34-64)

特点

  1. 可靠信号(不会丢失)

    • 如果同一个信号多次触发,会排队递送(保证每次信号都能被处理)。

    • 适用于需要精确事件计数的场景。

  2. 支持优先级

    • 编号小的实时信号优先递送(如 SIGRTMIN 优先于 SIGRTMIN+1)。

  3. 可携带附加信息

    • 通过 sa_sigaction 和 siginfo_t 结构体,可以获取:

      • 发送者 PID(si_pid

      • 用户数据(si_value,通过 sigqueue() 发送)

  4. 完全可控

    • 可以被捕获、阻塞或忽略(没有类似 SIGKILL 的强制限制)。

常见用途

  • 多线程编程中的线程间通信。

  • 高精度事件通知(如定时器、异步 I/O)。

http://www.xdnf.cn/news/16307.html

相关文章:

  • 佳能iR-ADV C5560复印机如何扫描文件到电脑
  • Gorm教程 - 关联
  • 电厂液压执行器自动化升级:Modbus TCP与DeviceNet的协议贯通实践
  • 微观低代码
  • SpringBoot实战指南:从快速入门到生产级部署(2025最新版)
  • 【运维】ubuntu 安装图形化界面
  • Vue2下
  • SQLFluff
  • Hive-vscode-snippets
  • [特殊字符] 第9篇:《SQL高阶 SELECT 技巧:DISTINCT、ORDER BY、LIMIT 全家桶》
  • CN3798-2A 降压型单节锂电池充电芯片
  • Androidstudio 上传当前module 或本地jar包到maven服务器。
  • 二分查找----6.寻找两个正序数组的中位数
  • Python 数据分析(一):NumPy 基础知识
  • PI 思维升级 PI设计的典范转移:从阻抗思维到谐振控制
  • 【办公类-107-03】20250725通义万相2.1“动物拟人化”视频,优化关键词(图片转视频MP4转gif))
  • 我的世界之战争星球 暮色苍茫篇 第二十三章、出发!暮色森林!
  • 【硬件-笔试面试题】硬件/电子工程师,笔试面试题-26,(知识点:硬件电路的调试方法:信号追踪,替换,分段调试)
  • 恋爱时间倒计时网页设计与实现方案
  • 数据仓库深度探索系列 | 开篇:开启数仓建设新征程
  • Homebrew 更换镜像源加速软件安装:详细操作指南
  • NVM踩坑实录:配置了npm的阿里云cdn之后,下载nodejs老版本(如:12.18.4)时,报404异常,下载失败的问题解决
  • 壁纸管理 API 文档
  • PPIO上线阿里旗舰推理模型Qwen3-235B-A22B-Thinking-2507
  • [特殊字符] VLA 如何“绕过”手眼标定?—— 当机器人学会了“看一眼就动手”
  • Qt 与 SQLite 嵌入式数据库开发
  • ✨ 使用 Flask 实现头像文件上传与加载功能
  • 工业缺陷检测的计算机视觉方法总结
  • 【C++ python cython】C++如何调用python,python 运行速度如何提高?
  • 工程项目管理软件评测:13款热门平台一览