Menu Close

进程间通信信号(Signals)详解

Linux 和 Unix 系统中,信号(Signal) 是一种进程间通信(IPC)机制,用于通知进程发生了某种事件。信号是一种异步的通知方式,操作系统或其他进程可以随时向目标进程发送信号,以让其执行特定的操作,如终止、暂停、继续运行等。


一) 什么是信号(Signals)?

  • 信号是进程间的异步通知机制,可以用于通知进程某个事件发生,如中断、终止、挂起等。
  • 进程可以接收、忽略、处理信号(但某些信号无法被捕获或忽略,如 SIGKILL)。
  • 信号是由 内核、用户、硬件 触发的。
  • 进程可以使用 kill 命令或 kill() 系统调用向其他进程发送信号。

二) 常见的 Linux 信号列表

信号编号 信号名称 默认动作 说明
1 SIGHUP 终止 终端关闭、会话结束时发送
2 SIGINT 终止 用户按 Ctrl+C 终止进程
3 SIGQUIT 终止 + Dump Ctrl+\ 退出进程,生成 core dump
9 SIGKILL 终止 强制终止进程,不可捕获/忽略
11 SIGSEGV 终止 + Dump 段错误(Segmentation Fault)
15 SIGTERM 终止 默认的进程终止信号,可被捕获和忽略
18 SIGCONT 继续 让一个停止的进程继续运行
19 SIGSTOP 停止 强制暂停进程,不可捕获/忽略
20 SIGTSTP 停止 Ctrl+Z 发送,让进程进入后台
  • SIGKILLSIGSTOP 无法被进程捕获或忽略,确保系统可以终止或挂起进程
  • SIGTERM最常用的终止进程信号,可由进程处理或忽略。

The number of possible signals is limited. The first 31 signals are standardized in LINUX; all have names starting with SIG. Some are from POSIX.

# Signal      Default     Comment                              POSIX
  Name        Action

 1 SIGHUP     Terminate   Hang up controlling terminal or      Yes
                          process 
 2 SIGINT     Terminate   Interrupt from keyboard, Control-C   Yes
 3 SIGQUIT    Dump        Quit from keyboard, Control-\        Yes
 4 SIGILL     Dump        Illegal instruction                  Yes
 5 SIGTRAP    Dump        Breakpoint for debugging             No
 6 SIGABRT    Dump        Abnormal termination                 Yes
 6 SIGIOT     Dump        Equivalent to SIGABRT                No
 7 SIGBUS     Dump        Bus error                            No
 8 SIGFPE     Dump        Floating-point exception             Yes
 9 SIGKILL    Terminate   Forced-process termination           Yes
10 SIGUSR1    Terminate   Available to processes               Yes
11 SIGSEGV    Dump        Invalid memory reference             Yes
12 SIGUSR2    Terminate   Available to processes               Yes
13 SIGPIPE    Terminate   Write to pipe with no readers        Yes
14 SIGALRM    Terminate   Real-timer clock                     Yes
15 SIGTERM    Terminate   Process termination                  Yes
16 SIGSTKFLT  Terminate   Coprocessor stack error              No
17 SIGCHLD    Ignore      Child process stopped or terminated  Yes
                          or got a signal if traced 
18 SIGCONT    Continue    Resume execution, if stopped         Yes
19 SIGSTOP    Stop        Stop process execution, Ctrl-Z       Yes
20 SIGTSTP    Stop        Stop process issued from tty         Yes
21 SIGTTIN    Stop        Background process requires input    Yes
22 SIGTTOU    Stop        Background process requires output   Yes
23 SIGURG     Ignore      Urgent condition on socket           No
24 SIGXCPU    Dump        CPU time limit exceeded              No
25 SIGXFSZ    Dump        File size limit exceeded             No
26 SIGVTALRM  Terminate   Virtual timer clock                  No
27 SIGPROF    Terminate   Profile timer clock                  No
28 SIGWINCH   Ignore      Window resizing                      No
29 SIGIO      Terminate   I/O now possible                     No
29 SIGPOLL    Terminate   Equivalent to SIGIO                  No
30 SIGPWR     Terminate   Power supply failure                 No
31 SIGSYS     Dump        Bad system call                      No
31 SIGUNUSED  Dump        Equivalent to SIGSYS                 No

Notice SIGUSR1 and SIGUSR2. These are available for customized use.

READ  Linux操作系统和Window操作系统有什么不同?

在终端运行kill -l命令, 可查看Linux支持的信号列表:

Linux支持的信号signal列表
Linux支持的信号signal列表

其中,编号为1 ~ 31的信号为传统UNIX支持的信号,是不可靠信号(非实时的);编号为34 ~ 63的信号是后来扩充的,为可靠信号(实时信号)。
不可靠信号和可靠信号的区别在于前者不支持排队,可能会造成信号丢失,而后者不会。

不可靠信号和可靠信号的区别在于前者不支持排队,可能会造成信号丢失,而后者不会。

1 SIGHUP 挂起(在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控制进程结束时, 通知同一session内的各个作业, 这时它们与控制终端不再关联)
2 SIGINT 中断(程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出,用于通知前台进程组终止进程
3 SIGQUIT 退出(和SIGINT类似, 但由QUIT字符(通常是Ctrl-/)来控制. 进程在因收到SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信号)
4 SIGILL 非法指令(执行了非法指令. 通常是因为可执行文件本身出现错误, 或者试图执行数据段. 堆栈溢出时也有可能产生这个信号)
5 SIGTRAP 断点或陷阱指令(由断点指令或其它trap指令产生. 由debugger使用)
6 SIGABRT abort发出的信号(调用abort函数生成的信号)
7 SIGBUS 非法内存访问(非法地址, 包括内存地址对齐(alignment)出错。比如访问一个四个字长的整数, 但其地址不是4的倍数。它与SIGSEGV的区别在于后者是由于对合法存储地址的非法访问触发的(如访问不属于自己存储空间或只读存储空间))
8 SIGFPE 浮点异常(在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术的错误)
9 SIGKILL kill信号(用来立即结束程序的运行) 不能被忽略、处理和阻塞
10 SIGUSR1 用户信号1(留给用户使用)
11 SIGSEGV 无效内存访问(试图访问未分配给自己的内存, 或试图往没有写权限的内存地址写数据)
12 SIGUSR2 用户信号2(留给用户使用)
13 SIGPIPE 管道破损,没有读端的管道写数据(这个信号通常在进程间通信产生,比如采用FIFO(管道)通信的两个进程,读管道没打开或者意外终止还往管道写,写进程会收到SIGPIPE信号。此外用Socket通信的两个进程,写进程在写Socket的时候,读进程已经终止,也会产生这个信号)
14 SIGALRM alarm发出的信号(时钟定时信号, 计算的是实际的时间或时钟时间. alarm函数使用该信号)
15 SIGTERM 终止信号(程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理。通常用来要求程序自己正常退出,shell命令kill缺省产生这个信号)
16 SIGSTKFLT 栈溢出
17 SIGCHLD 子进程退出(子进程结束时, 父进程会收到这个信号) 默认忽略
18 SIGCONT 进程继续 不能被阻塞
19 SIGSTOP 进程停止(停止(stopped)进程的执行. 注意它和terminate以及interrupt的区别:该进程还未结束, 只是暂停执行) 不能被忽略、处理和阻塞
20 SIGTSTP 进程停止(停止进程的运行, 用户键入SUSP字符时(通常是Ctrl-Z)发出这个信号) 该信号可以被处理和忽略
21 SIGTTIN 进程停止,后台进程从终端读数据时
22 SIGTTOU 进程停止,后台进程想终端写数据时
23 SIGURG I/O有紧急数据到达当前进程 默认忽略
24 SIGXCPU 进程CPU时间片到期
25 SIGXFSZ 文件大小的超出上限
26 SIGVTALRM 虚拟时钟超时
27 SIGPROF profile时钟超时
28 SIGWINCH 窗口大小改变 默认忽略
29 SIGIO I/O相关
30 SIGPWR 关机 默认忽略
31 SIGSYS 系统调用异常
参考博文:


三) 发送信号

3.1) kill 命令

kill 用于向进程发送信号:

kill -SIGNAL PID
kill -9 1234  # 发送 SIGKILL 终止进程 1234
kill -15 5678 # 发送 SIGTERM(默认)终止进程 5678

如果不指定信号,默认发送 SIGTERM

kill 5678  # 等价于 kill -15 5678

3.2)pkillkillall

pkill 通过进程发送信号:

pkill -9 firefox  # 强制终止所有名为 firefox 的进程

killall 终止所有匹配名称的进程

killall -15 python  # 发送 SIGTERM 终止所有 Python 进程

3.3) kill() 系统调用

在 C 语言中,可以使用 kill() 发送信号:

#include <signal.h>
#include <unistd.h>
#include <stdio.h>

int main() {
    pid_t pid = 1234; // 替换为目标进程 PID
    kill(pid, SIGKILL); // 向进程发送 SIGKILL
    return 0;
}

3.4)raise() 向自己发送信号

#include <signal.h>
#include <stdio.h>

int main() {
    printf("Sending SIGTERM to self...\n");
    raise(SIGTERM); // 进程向自己发送 SIGTERM
    return 0;
}

3.5)sigqueue() 发送带数据的信号

#include <signal.h>
#include <stdio.h>

int main() {
    pid_t pid = 1234; // 目标进程 PID
    union sigval value;
    value.sival_int = 42; // 传递的数据
    sigqueue(pid, SIGTERM, value);
    return 0;
}

四) 处理信号

进程可以使用 signal()sigaction() 处理信号。

READ  Linux内核源代码的目录结构

4.1) signal() 处理信号

#include <signal.h>
#include <stdio.h>
#include <unistd.h>

void handler(int signum) {
    printf("Received signal %d\n", signum);
}

int main() {
    signal(SIGINT, handler); // 捕获 SIGINT (Ctrl+C)
    while (1) {
        sleep(1);
    }
    return 0;
}

运行后,按 Ctrl+C 发送 SIGINT进程不会终止,而是打印 Received signal 2

4.2) sigaction() 处理信号

sigaction() 提供更强的信号控制功能:

#include <signal.h>
#include <stdio.h>
#include <unistd.h>

void handler(int signum) {
    printf("Caught signal %d\n", signum);
}

int main() {
    struct sigaction sa;
    sa.sa_handler = handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

    sigaction(SIGINT, &sa, NULL);
    while (1) {
        sleep(1);
    }
    return 0;
}

sigaction() 可以替代 signal(),支持更高级的信号处理。

五)屏蔽信号

 sigprocmask() 屏蔽信号

可以使用 sigprocmask() 屏蔽信号,使进程暂时忽略某些信号:

#include <signal.h>
#include <stdio.h>
#include <unistd.h>

int main() {
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGINT); // 屏蔽 SIGINT

    sigprocmask(SIG_BLOCK, &set, NULL);
    printf("SIGINT is blocked. Press Ctrl+C, but nothing happens.\n");
    sleep(10);

    sigprocmask(SIG_UNBLOCK, &set, NULL);
    printf("SIGINT is now unblocked.\n");

    while (1) sleep(1);
    return 0;
}

SIG_BLOCK 屏蔽信号,SIG_UNBLOCK 解除屏蔽。

六) 挂起进程等待信号

6.1) pause() 等待信号

#include <signal.h>
#include <stdio.h>
#include <unistd.h>

void handler(int signum) {
    printf("Caught signal %d, exiting...\n", signum);
}

int main() {
    signal(SIGINT, handler);
    printf("Waiting for signal...\n");
    pause();  // 挂起进程,直到接收到信号
    return 0;
}

6.2) sigwait() 主动等待信号

#include <signal.h>
#include <stdio.h>

int main() {
    sigset_t set;
    int signum;

    sigemptyset(&set);
    sigaddset(&set, SIGINT);
    sigprocmask(SIG_BLOCK, &set, NULL);

    printf("Waiting for SIGINT...\n");
    sigwait(&set, &signum);
    printf("Received signal %d\n", signum);

    return 0;
}

7. 总结

  • 信号是进程间通信的重要方式,用于通知进程发生事件,如终止、暂停、继续等。
  • 进程可以使用 killraisesigqueue 发送信号。
  • 进程可以使用 signal()sigaction() 处理信号。
  • 可以使用 sigprocmask() 屏蔽信号,pause()sigwait() 挂起进程等待信号。

掌握信号机制对编写可靠的后台服务、守护进程、异常处理等至关重要!

除教程外,本网站大部分文章来自互联网,如果有内容冒犯到你,请联系我们删除!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

Leave the field below empty!

Posted in 进程

Related Posts