Linux 信号详解

目录

前言

一、什么是信号?

1.信号的特点

二、信号的基本概念

1.信号的生命周期

2.信号编号与名称

3.信号的来源

三、常见信号列表

1.标准信号(1-31)

2.重要信号详解

[(1)SIGINT (2) - 中断信号](#(1)SIGINT (2) - 中断信号)

[(2)SIGKILL (9) - 强制终止](#(2)SIGKILL (9) - 强制终止)

[(3)SIGTERM (15) - 正常终止](#(3)SIGTERM (15) - 正常终止)

[(4)SIGSEGV (11) - 段错误](#(4)SIGSEGV (11) - 段错误)

[(5)SIGCHLD (17) - 子进程状态改变](#(5)SIGCHLD (17) - 子进程状态改变)

四、信号的产生方式

[1. 终端按键产生](#1. 终端按键产生)

[2. 硬件异常产生](#2. 硬件异常产生)

[3. 系统调用产生](#3. 系统调用产生)

[(1)kill() 函数](#(1)kill() 函数)

[(2)raise() 函数](#(2)raise() 函数)

[(3)abort() 函数](#(3)abort() 函数)

[4. 软件条件产生](#4. 软件条件产生)

[(1)alarm() 函数](#(1)alarm() 函数)

[(2)setitimer() 函数](#(2)setitimer() 函数)

五、信号的处理方式

1.三种处理方式

[2.signal() 函数(传统方式)](#2.signal() 函数(传统方式))

[3.sigaction() 函数(推荐方式)](#3.sigaction() 函数(推荐方式))

[(1)sigaction 使用示例](#(1)sigaction 使用示例)

[(2)使用 SA_SIGINFO 获取详细信息](#(2)使用 SA_SIGINFO 获取详细信息)

六、信号集操作

1.信号集类型

2.信号集操作函数

3.信号集操作示例

七、信号的阻塞与未决

1.基本概念

2.信号阻塞相关函数

3.信号阻塞示例

4.信号处理流程图

八、实时信号

1.实时信号特点

2.实时信号操作

4.实时信号示例

九、信号处理的最佳实践

[1. 信号处理函数的安全要求](#1. 信号处理函数的安全要求)

[2. 使用自管道(Self-Pipe)技巧](#2. 使用自管道(Self-Pipe)技巧)

[3. 优雅的信号处理模式](#3. 优雅的信号处理模式)

[4. 子进程信号处理](#4. 子进程信号处理)

[5. 信号安全日志记录](#5. 信号安全日志记录)

九、常用命令参考

1.发送信号

2.查看信号信息

3.信号调试

十、总结


前言

信号是Linux/Unix系统中的异步事件通知机制,用于进程间通信和异常处理。

本文系统介绍了信号的基本概念、常见信号类型(如SIGINT、SIGKILL、SIGTERM等)、信号产生方式(终端按键、硬件异常、系统调用等)以及信号处理方法(signal/sigaction)。

重点阐述了信号阻塞、实时信号特性,并提供了信号处理的最佳实践,包括安全函数使用、自管道技巧和子进程处理方案。

文章还包含常用命令参考,可帮助开发者们正确使用信号机制进行进程管理和异常处理。


一、什么是信号?

信号(Signal) 是 Linux/Unix 系统中一种异步事件通知机制 ,用于通知进程发生了某个特定事件。信号是软件中断的一种形式,它提供了一种处理异步事件的方法。

1.信号的特点

  • 异步性:信号可以在任何时候发送给进程,进程无法预知信号何时到达
  • 简单性:信号携带的信息量很少,仅表示某种事件的发生
  • 优先级:信号的处理会打断进程的正常执行流程
  • 可处理性:进程可以选择捕获、忽略或执行默认操作

二、信号的基本概念

1.信号的生命周期

复制代码
信号产生 → 信号注册 → 信号处理

2.信号编号与名称

每个信号都有一个唯一的整数编号(1-31 为标准信号,34-64 为实时信号)和一个符号名称(如 SIGINTSIGKILL)。

3.信号的来源

来源类型 说明 示例
终端输入 用户通过键盘发送 Ctrl+C, Ctrl+\
硬件异常 硬件错误产生 除零错误、非法内存访问
系统调用 通过函数发送 kill(), raise(), alarm()
软件条件 特定软件条件 定时器到期、管道断开

三、常见信号列表

1.标准信号(1-31)

信号 编号 默认动作 说明
SIGHUP 1 终止 挂起信号,终端断开时发送
SIGINT 2 终止 中断信号,Ctrl+C 产生
SIGQUIT 3 终止+核心转储 退出信号,Ctrl+\ 产生
SIGILL 4 终止+核心转储 非法指令
SIGTRAP 5 终止+核心转储 跟踪/断点陷阱
SIGABRT 6 终止+核心转储 异常终止(abort)
SIGBUS 7 终止+核心转储 总线错误
SIGFPE 8 终止+核心转储 浮点运算异常
SIGKILL 9 终止 强制终止,不可捕获/忽略
SIGUSR1 10 终止 用户自定义信号1
SIGSEGV 11 终止+核心转储 段错误(非法内存访问)
SIGUSR2 12 终止 用户自定义信号2
SIGPIPE 13 终止 管道破裂(写入无读端管道)
SIGALRM 14 终止 定时器信号(alarm)
SIGTERM 15 终止 正常终止信号
SIGCHLD 17 忽略 子进程状态改变
SIGCONT 18 继续 继续执行暂停的进程
SIGSTOP 19 暂停 暂停进程,不可捕获/忽略
SIGTSTP 20 暂停 终端暂停信号,Ctrl+Z 产生
SIGTTIN 21 暂停 后台进程读终端
SIGTTOU 22 暂停 后台进程写终端

2.重要信号详解

(1)SIGINT (2) - 中断信号
复制代码
# 按 Ctrl+C 发送
# 默认行为:终止进程
# 常用于:优雅地终止前台进程
(2)SIGKILL (9) - 强制终止
复制代码
kill -9 <pid>
# 特点:
# - 无法被捕获、阻塞或忽略
# - 立即终止进程
# - 进程无法进行清理操作
# 建议:仅在无法正常终止时使用
(3)SIGTERM (15) - 正常终止
复制代码
kill <pid>        # 默认发送 SIGTERM
kill -15 <pid>
# 特点:
# - 可以被捕获和处理
# - 允许进程进行清理操作
# - 推荐的首选终止方式
(4)SIGSEGV (11) - 段错误
复制代码
// 常见原因:
// - 访问未分配的内存
// - 访问已释放的内存
// - 数组越界访问
// - 解引用空指针

int *p = NULL;
*p = 10;  // 触发 SIGSEGV
(5)SIGCHLD (17) - 子进程状态改变
复制代码
// 子进程终止或停止时发送给父进程
// 默认行为:忽略
// 常用于:防止僵尸进程

四、信号的产生方式

1. 终端按键产生

bash 复制代码
Ctrl+C  → SIGINT   (中断)
Ctrl+\  → SIGQUIT  (退出)
Ctrl+Z  → SIGTSTP  (暂停)

2. 硬件异常产生

bash 复制代码
// 除零错误 → SIGFPE
int a = 10 / 0;

// 非法内存访问 → SIGSEGV
int *p = (int *)0x12345;
*p = 100;

3. 系统调用产生

(1)kill() 函数
bash 复制代码
#include <signal.h>
#include <sys/types.h>

int kill(pid_t pid, int sig);
// 功能:向指定进程发送信号
// 参数:
//   pid > 0: 发送给指定进程
//   pid = 0: 发送给同组所有进程
//   pid = -1: 发送给所有有权限的进程
//   pid < -1: 发送给进程组 |pid| 中的所有进程
// 返回值:成功返回0,失败返回-1

// 示例
kill(1234, SIGTERM);   // 向PID为1234的进程发送SIGTERM
kill(0, SIGUSR1);      // 向同组所有进程发送SIGUSR1
(2)raise() 函数
bash 复制代码
#include <signal.h>

int raise(int sig);
// 功能:向当前进程自身发送信号
// 等价于:kill(getpid(), sig)

// 示例
raise(SIGTERM);  // 自我终止
(3)abort() 函数
bash 复制代码
#include <stdlib.h>

void abort(void);
// 功能:异常终止程序,产生 SIGABRT 信号
// 特点:会生成核心转储文件(如果允许)

4. 软件条件产生

(1)alarm() 函数
bash 复制代码
#include <unistd.h>

unsigned int alarm(unsigned int seconds);
// 功能:设置定时器,seconds秒后发送 SIGALRM 信号
// 返回值:返回上次定时器剩余时间,无上次定时器返回0
// 注意:每个进程只能有一个alarm定时器

// 示例
#include <stdio.h>
#include <unistd.h>
#include <signal.h>

void alarm_handler(int sig) {
    printf("定时器到期!\n");
}

int main() {
    signal(SIGALRM, alarm_handler);
    alarm(5);  // 5秒后发送SIGALRM
    
    printf("等待定时器...\n");
    pause();   // 等待信号
    
    return 0;
}
(2)setitimer() 函数
复制代码
#include <sys/time.h>

int setitimer(int which, const struct itimerval *new_value,
              struct itimerval *old_value);
// 功能:设置高精度定时器
// which参数:
//   ITIMER_REAL: 真实时间,发送 SIGALRM
//   ITIMER_VIRTUAL: 用户态CPU时间,发送 SIGVTALRM
//   ITIMER_PROF: 用户态+内核态CPU时间,发送 SIGPROF

struct itimerval {
    struct timeval it_interval;  // 间隔时间(周期性定时)
    struct timeval it_value;     // 首次到期时间
};

struct timeval {
    time_t tv_sec;      // 秒
    suseconds_t tv_usec; // 微秒
};

五、信号的处理方式

1.三种处理方式

  1. 默认动作(Default):执行系统预设的操作
  2. 忽略信号(Ignore):丢弃信号,不执行任何操作
  3. 捕获信号(Catch):执行自定义的信号处理函数

2.signal() 函数(传统方式)

bash 复制代码
#include <signal.h>

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);
// 参数:
//   signum: 信号编号
//   handler: 处理方式
//     SIG_DFL: 默认处理
//     SIG_IGN: 忽略信号
//     自定义函数指针: 捕获信号

// 示例代码
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

// 自定义信号处理函数
void sigint_handler(int sig) {
    printf("\n捕获到 SIGINT 信号(编号:%d)\n", sig);
    printf("正在执行清理工作...\n");
    // 执行清理操作
    _exit(0);  // 安全退出
}

int main() {
    // 设置 SIGINT 的处理方式
    if (signal(SIGINT, sigint_handler) == SIG_ERR) {
        perror("signal");
        return 1;
    }
    
    printf("按 Ctrl+C 测试信号处理(PID: %d)\n", getpid());
    
    while (1) {
        printf("工作中...\n");
        sleep(2);
    }
    
    return 0;
}

3.sigaction() 函数(推荐方式)

bash 复制代码
#include <signal.h>

int sigaction(int signum, const struct sigaction *act,
              struct sigaction *oldact);
// 功能:更强大的信号处理设置函数
// 参数:
//   signum: 信号编号
//   act: 新的处理方式(NULL表示不设置)
//   oldact: 保存旧的处理方式(NULL表示不保存)

struct sigaction {
    void (*sa_handler)(int);           // 信号处理函数
    void (*sa_sigaction)(int, siginfo_t *, void *); // 高级处理函数
    sigset_t sa_mask;                   // 信号屏蔽字
    int sa_flags;                       // 标志位
    void (*sa_restorer)(void);          // 已废弃
};

// sa_flags 常用标志
#define SA_RESTART      // 自动重启被中断的系统调用
#define SA_NODEFER      // 不自动阻塞该信号
#define SA_RESETHAND    // 执行后恢复默认处理
#define SA_SIGINFO      // 使用 sa_sigaction 处理函数
(1)sigaction 使用示例
bash 复制代码
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>

void sigint_handler(int sig) {
    write(STDOUT_FILENO, "\n收到 SIGINT,优雅退出\n", 25);
    _exit(0);
}

int main() {
    struct sigaction sa;
    
    // 清空结构体
    memset(&sa, 0, sizeof(sa));
    
    // 设置处理函数
    sa.sa_handler = sigint_handler;
    
    // 设置标志:自动重启被中断的系统调用
    sa.sa_flags = SA_RESTART;
    
    // 清空信号屏蔽字
    sigemptyset(&sa.sa_mask);
    
    // 安装信号处理器
    if (sigaction(SIGINT, &sa, NULL) == -1) {
        perror("sigaction");
        return 1;
    }
    
    printf("按 Ctrl+C 退出(PID: %d)\n", getpid());
    
    while (1) {
        printf("运行中...\n");
        sleep(2);
    }
    
    return 0;
}
(2)使用 SA_SIGINFO 获取详细信息
bash 复制代码
#define _GNU_SOURCE
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void advanced_handler(int sig, siginfo_t *info, void *context) {
    printf("\n=== 信号详细信息 ===\n");
    printf("信号编号: %d\n", sig);
    printf("发送进程PID: %d\n", info->si_pid);
    printf("发送进程UID: %d\n", info->si_uid);
    printf("信号值: %d\n", info->si_value.sival_int);
    printf("==================\n");
}

int main() {
    struct sigaction sa;
    
    sa.sa_sigaction = advanced_handler;
    sa.sa_flags = SA_SIGINFO;  // 使用三参数处理函数
    sigemptyset(&sa.sa_mask);
    
    sigaction(SIGUSR1, &sa, NULL);
    
    printf("等待 SIGUSR1 信号(PID: %d)\n", getpid());
    
    while (1) {
        pause();
    }
    
    return 0;
}

六、信号集操作

1.信号集类型

bash 复制代码
#include <signal.h>

typedef struct {
    unsigned long sig[(64 + 8 * sizeof(unsigned long) - 1) / 
                      (8 * sizeof(unsigned long))];
} sigset_t;
// 用于表示一组信号的位图结构

2.信号集操作函数

bash 复制代码
#include <signal.h>

// 清空信号集
int sigemptyset(sigset_t *set);

// 填充所有信号到信号集
int sigfillset(sigset_t *set);

// 添加单个信号到信号集
int sigaddset(sigset_t *set, int signum);

// 从信号集中删除单个信号
int sigdelset(sigset_t *set, int signum);

// 检查信号是否在信号集中
int sigismember(const sigset_t *set, int signum);

3.信号集操作示例

bash 复制代码
#include <stdio.h>
#include <signal.h>

int main() {
    sigset_t set;
    
    // 清空信号集
    sigemptyset(&set);
    
    // 添加 SIGINT 和 SIGTERM
    sigaddset(&set, SIGINT);
    sigaddset(&set, SIGTERM);
    
    // 检查 SIGINT 是否在集合中
    if (sigismember(&set, SIGINT)) {
        printf("SIGINT 在信号集中\n");
    }
    
    // 检查 SIGKILL 是否在集合中
    if (!sigismember(&set, SIGKILL)) {
        printf("SIGKILL 不在信号集中\n");
    }
    
    // 删除 SIGINT
    sigdelset(&set, SIGINT);
    
    // 填充所有信号
    sigfillset(&set);
    printf("信号集已填充所有信号\n");
    
    return 0;
}

七、信号的阻塞与未决

1.基本概念

  • 信号阻塞(Blocked) :信号被阻塞后,不会立即递达,而是保持未决状态
  • 信号未决(Pending):信号已产生但尚未被处理的状态
  • 信号递达(Delivered):信号被处理的时刻

2.信号阻塞相关函数

bash 复制代码
#include <signal.h>

// 检查或修改进程的信号屏蔽字
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
// how参数:
//   SIG_BLOCK: 将set中的信号添加到屏蔽字
//   SIG_UNBLOCK: 从屏蔽字中移除set中的信号
//   SIG_SETMASK: 将屏蔽字设置为set

// 获取当前未决信号集
int sigpending(sigset_t *set);

3.信号阻塞示例

bash 复制代码
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void handler(int sig) {
    printf("处理信号: %d\n", sig);
}

int main() {
    sigset_t block_set, pending_set;
    
    // 设置 SIGINT 处理函数
    signal(SIGINT, handler);
    
    // 创建要阻塞的信号集
    sigemptyset(&block_set);
    sigaddset(&block_set, SIGINT);
    
    printf("阻塞 SIGINT 5秒,请在这5秒内按 Ctrl+C\n");
    
    // 阻塞 SIGINT
    sigprocmask(SIG_BLOCK, &block_set, NULL);
    
    sleep(5);
    
    // 检查未决信号
    sigpending(&pending_set);
    if (sigismember(&pending_set, SIGINT)) {
        printf("SIGINT 处于未决状态\n");
    }
    
    printf("解除阻塞,信号将被处理\n");
    
    // 解除阻塞
    sigprocmask(SIG_UNBLOCK, &block_set, NULL);
    
    sleep(1);
    printf("程序结束\n");
    
    return 0;
}

4.信号处理流程图

复制代码
┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   信号产生   │ ──→ │   信号未决   │ ──→ │   信号递达   │
│  (Generated)│     │  (Pending)  │     │ (Delivered) │
└─────────────┘     └─────────────┘     └─────────────┘
                            ↑
                            │ 信号被阻塞
                      ┌─────────────┐
                      │   信号阻塞   │
                      │  (Blocked)  │
                      └─────────────┘

八、实时信号

1.实时信号特点

特性 标准信号 实时信号
编号范围 1-31 34-64
排队 不支持(相同信号只保留一个) 支持(多个相同信号排队)
携带数据 不能 可以(通过 sigqueue)
优先级 编号小的优先
用途 系统预定义 用户自定义

2.实时信号操作

bash 复制代码
#include <signal.h>
#include <unistd.h>

// 发送带数据的实时信号
int sigqueue(pid_t pid, int sig, const union sigval value);

union sigval {
    int sival_int;      // 整型数据
    void *sival_ptr;    // 指针数据(仅同一进程内有效)
};

4.实时信号示例

bash 复制代码
#define _GNU_SOURCE
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void rt_handler(int sig, siginfo_t *info, void *context) {
    printf("收到实时信号 %d,数据: %d\n", sig, info->si_value.sival_int);
}

int main() {
    struct sigaction sa;
    pid_t pid = getpid();
    
    sa.sa_sigaction = rt_handler;
    sa.sa_flags = SA_SIGINFO;
    sigemptyset(&sa.sa_mask);
    
    // 注册实时信号处理函数
    sigaction(SIGRTMIN, &sa, NULL);
    
    printf("进程 PID: %d\n", pid);
    printf("向自己发送3个实时信号...\n");
    
    // 发送带数据的实时信号
    union sigval value;
    for (int i = 1; i <= 3; i++) {
        value.sival_int = i * 100;
        sigqueue(pid, SIGRTMIN, value);
    }
    
    sleep(1);
    return 0;
}

九、信号处理的最佳实践

1. 信号处理函数的安全要求

信号处理函数中只能调用异步信号安全函数:

bash 复制代码
// ✅ 安全的函数
write(), _exit(), kill(), sigaction()
getpid(), getppid(), sleep()

// ❌ 不安全的函数(避免使用)
printf(), malloc(), free(), exit()
fopen(), fread(), fwrite()
pthread_mutex_lock(), 大部分库函数

2. 使用自管道(Self-Pipe)技巧

bash 复制代码
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/select.h>

static int pipefd[2];

void signal_handler(int sig) {
    // 只写入一个字节到管道
    write(pipefd[1], &sig, 1);
}

int main() {
    fd_set readfds;
    char sig;
    
    // 创建管道
    pipe(pipefd);
    fcntl(pipefd[0], F_SETFL, O_NONBLOCK);
    fcntl(pipefd[1], F_SETFL, O_NONBLOCK);
    
    // 设置信号处理
    signal(SIGINT, signal_handler);
    signal(SIGTERM, signal_handler);
    
    printf("使用 select 等待信号(PID: %d)\n", getpid());
    
    while (1) {
        FD_ZERO(&readfds);
        FD_SET(pipefd[0], &readfds);
        
        select(pipefd[0] + 1, &readfds, NULL, NULL, NULL);
        
        if (FD_ISSET(pipefd[0], &readfds)) {
            read(pipefd[0], &sig, 1);
            printf("主循环中处理信号: %d\n", (int)sig);
            
            if (sig == SIGINT || sig == SIGTERM) {
                printf("退出程序\n");
                break;
            }
        }
    }
    
    close(pipefd[0]);
    close(pipefd[1]);
    return 0;
}

3. 优雅的信号处理模式

bash 复制代码
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdatomic.h>

// 使用原子变量作为信号标志
static atomic_int signal_received = 0;

void signal_handler(int sig) {
    // 只设置标志,不做复杂操作
    atomic_store(&signal_received, sig);
}

void process_work() {
    // 模拟工作
    static int counter = 0;
    printf("工作进行中... %d\n", ++counter);
    sleep(1);
}

void cleanup() {
    printf("执行清理操作...\n");
    // 关闭文件、释放资源等
}

int main() {
    struct sigaction sa;
    
    sa.sa_handler = signal_handler;
    sa.sa_flags = SA_RESTART;
    sigemptyset(&sa.sa_mask);
    
    sigaction(SIGINT, &sa, NULL);
    sigaction(SIGTERM, &sa, NULL);
    
    printf("程序运行中(PID: %d)\n", getpid());
    
    while (1) {
        process_work();
        
        // 在主循环中检查信号
        int sig = atomic_load(&signal_received);
        if (sig != 0) {
            printf("\n收到信号 %d,准备退出\n", sig);
            cleanup();
            break;
        }
    }
    
    return 0;
}

4. 子进程信号处理

bash 复制代码
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>

void sigchld_handler(int sig) {
    int status;
    pid_t pid;
    
    // 使用 WNOHANG 非阻塞等待所有子进程
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
        printf("子进程 %d 已退出\n", pid);
    }
}

int main() {
    struct sigaction sa;
    
    // 设置 SIGCHLD 处理函数,防止僵尸进程
    sa.sa_handler = sigchld_handler;
    sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
    sigemptyset(&sa.sa_mask);
    
    sigaction(SIGCHLD, &sa, NULL);
    
    // 创建子进程
    for (int i = 0; i < 3; i++) {
        pid_t pid = fork();
        if (pid == 0) {
            // 子进程
            printf("子进程 %d 启动\n", getpid());
            sleep(2 + i);
            printf("子进程 %d 退出\n", getpid());
            _exit(0);
        }
    }
    
    printf("父进程等待子进程...\n");
    
    // 父进程继续工作
    for (int i = 0; i < 10; i++) {
        printf("父进程工作中...\n");
        sleep(1);
    }
    
    return 0;
}

5. 信号安全日志记录

bash 复制代码
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>

// 信号安全的日志函数
void safe_log(const char *msg) {
    // 使用 write 而不是 printf
    write(STDOUT_FILENO, msg, strlen(msg));
    write(STDOUT_FILENO, "\n", 1);
}

void handler(int sig) {
    const char *msg;
    switch (sig) {
        case SIGINT:  msg = "收到 SIGINT"; break;
        case SIGTERM: msg = "收到 SIGTERM"; break;
        case SIGALRM: msg = "收到 SIGALRM"; break;
        default:      msg = "收到未知信号"; break;
    }
    safe_log(msg);
}

int main() {
    signal(SIGINT, handler);
    signal(SIGTERM, handler);
    signal(SIGALRM, handler);
    
    alarm(3);
    
    safe_log("程序启动,3秒后收到SIGALRM");
    
    while (1) {
        pause();
    }
    
    return 0;
}

九、常用命令参考

1.发送信号

bash 复制代码
# 发送 SIGTERM(默认)
kill <pid>

# 发送特定信号
kill -SIGINT <pid>
kill -2 <pid>        # 数字形式
kill -9 <pid>        # 强制终止

# 向进程组发送信号
kill -TERM -<pgid>

# 使用 pkill 按名称发送
pkill -INT process_name
pkill -f "pattern"

# 使用 killall
killall -TERM process_name

2.查看信号信息

bash 复制代码
# 列出所有信号
kill -l

# 查看信号编号对应的名称
kill -l 9    # 输出: KILL
kill -l 15   # 输出: TERM

# 查看信号帮助
man 7 signal
man sigaction

3.信号调试

bash 复制代码
# 使用 strace 跟踪信号
strace -e trace=signal ./program

# 查看进程挂起的信号
cat /proc/<pid>/status | grep Sig
# SigPnd: 线程组共享的未决信号
# SigBlk: 阻塞的信号
# SigIgn: 忽略的信号
# SigCgt: 捕获的信号

十、总结

要点 说明
信号本质 软件中断,异步事件通知机制
可靠信号 SIGKILL (9) 和 SIGSTOP (19) 不可捕获/忽略
推荐终止 优先使用 SIGTERM (15),允许进程清理
推荐API 使用 sigaction() 替代 signal()
处理安全 信号处理器中只使用异步信号安全函数
实时信号 支持排队和携带数据,用于应用自定义
相关推荐
放飞梦想C2 小时前
CPU Cache
linux·cache
Hoshino.413 小时前
基于Linux中的数据库操作——下载与安装(1)
linux·运维·数据库
恒创科技HK4 小时前
通用型云服务器与计算型云服务器:您真正需要哪些配置?
运维·服务器
吴佳浩 Alben4 小时前
GPU 生产环境实践:硬件拓扑、显存管理与完整运维体系
运维·人工智能·pytorch·语言模型·transformer·vllm
播播资源5 小时前
CentOS系统 + 宝塔面板 部署 OpenClaw源码开发版完整教程
linux·运维·centos
源远流长jerry5 小时前
在 Ubuntu 22.04 上配置 Soft-RoCE 并运行 RDMA 测试程序
linux·服务器·网络·tcp/ip·ubuntu·架构·ip
学不完的5 小时前
Docker数据卷管理及优化
运维·docker·容器·eureka
lay_liu5 小时前
Linux安装redis
linux·运维·redis
虾..6 小时前
UDP协议
网络·网络协议·udp