跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
搜索
|注册
博客列表

目录

  1. 引言
  2. sigaction 函数概述
  3. struct sigaction 结构体
  4. 关键成员解析
  5. sigaction 的核心优势
  6. 使用示例
  7. 基本用法
  8. 高级用法(使用 SA_SIGINFO)
  9. 信号处理的最佳实践
  10. 常见问题与解决方案
  11. 1. 系统调用被信号中断
  12. 2. 信号处理函数中调用不可重入函数
  13. 3. 信号丢失
  14. 与 signal() 函数的比较
  15. 结论
C

Linux sigaction 函数详解:信号处理机制与最佳实践

Linux sigaction 函数提供比 signal 更可靠的信号处理机制,支持信号屏蔽、附加信息及系统调用重启控制。通过 struct sigaction 结构体可精细配置处理动作与标志位。示例涵盖基本用法及 SA_SIGINFO 高级特性。最佳实践要求处理函数保持简单、使用异步信号安全函数及 volatile sig_atomic_t 共享变量。开发者应优先采用 sigaction 构建健壮应用以应对复杂异步事件。

怪力乱神发布于 2026/2/5更新于 2026/4/183.3K 浏览
Linux sigaction 函数详解:信号处理机制与最佳实践

引言

在 Linux 系统编程中,信号处理是一个非常重要的主题。信号是进程间通信的一种基本方式,用于通知进程发生了某种事件。传统的 signal() 函数虽然简单易用,但在功能性和可移植性方面存在诸多限制。而 sigaction() 函数提供了更强大、更灵活的信号处理机制,是现代 Linux 程序设计中处理信号的首选方式。

sigaction 函数概述

sigaction() 函数允许我们检查或指定与特定信号相关联的处理动作,其函数原型如下:

#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

参数说明:

  • signum:要操作的信号编号(如 SIGINT、SIGTERM 等)
  • act:指向新的信号处理动作的指针
  • oldact:用于保存之前的信号处理动作(可为 NULL)

返回值:

  • 成功时返回 0,失败时返回 -1 并设置 errno

struct sigaction 结构体

sigaction 结构体定义了信号处理的各种属性:

struct sigaction {
    void (*sa_handler)(int); // 信号处理函数
    void (*sa_sigaction)(int, siginfo_t *, void *); // 带有额外信息的处理函数
    sigset_t sa_mask; // 阻塞信号集
    int sa_flags; // 标志位
    void (*sa_restorer)(void); // 已废弃
};

关键成员解析

  1. sa_handler:传统的信号处理函数指针,与 signal() 函数使用的处理函数类型相同。
  2. sa_sigaction:更高级的信号处理函数指针,可以接收额外的信号信息。当 sa_flags 包含 SA_SIGINFO 标志时使用此处理函数。
  3. sa_mask:在执行信号处理函数期间,需要阻塞的信号集。这可以防止信号处理函数被其他信号中断。
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog

更多推荐文章

查看全部
  • Linux 高级 IO:基于 ET 模式 epoll 的 Reactor 模型 TCP 服务器实现
  • Linux 信号量详解与基于环形队列的生产消费模型实现
  • ArkTS 驱动鸿蒙元服务开发:界面布局与交互逻辑实战
  • AI 大模型驱动的软件开发全流程变革:从需求分析到智能运维
  • 非标自动化教学系列课程
  • NVIDIA AI Enterprise 运维指南:医疗行业部署与训练路径
  • Qt 与 Linux Socket 跨平台通信深度解析

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online

  • sa_flags:控制信号行为的各种标志,常见的有:
    • SA_RESTART:被信号中断的系统调用自动重启
    • SA_SIGINFO:使用 sa_sigaction 而非 sa_handler 作为处理函数
    • SA_NOCLDSTOP:对于 SIGCHLD 信号,不接收子进程停止的通知
    • SA_NODEFER:不阻塞当前信号(不自动将当前信号加入信号掩码)
  • sigaction 的核心优势

    相比传统的 signal() 函数,sigaction() 具有以下显著优势:

    1. 更可靠的信号处理:提供了对信号处理过程的更精细控制
    2. 信号屏蔽:可以指定在处理当前信号时阻塞哪些其他信号
    3. 附加信息:通过 SA_SIGINFO 标志可以获取关于信号的更多上下文信息
    4. 可移植性:在不同 UNIX 系统上行为一致
    5. 系统调用重启:通过 SA_RESTART 标志可以自动重启被中断的系统调用

    使用示例

    基本用法

    #include <stdio.h>
    #include <stdlib.h>
    #include <signal.h>
    #include <unistd.h>
    
    void handler(int sig) {
        printf("Received signal %d\n", sig);
    }
    
    int main() {
        struct sigaction sa;
        sa.sa_handler = handler;
        sigemptyset(&sa.sa_mask);
        sa.sa_flags = 0;
        if (sigaction(SIGINT, &sa, NULL) == -1) {
            perror("sigaction");
            exit(EXIT_FAILURE);
        }
        while (1) {
            printf("Waiting for signal...\n");
            sleep(1);
        }
        return 0;
    }
    

    高级用法(使用 SA_SIGINFO)

    #include <stdio.h>
    #include <stdlib.h>
    #include <signal.h>
    #include <unistd.h>
    #include <string.h>
    
    void handler(int sig, siginfo_t *info, void *ucontext) {
        printf("Received signal %d from process %d\n", sig, info->si_pid);
        printf("Additional data: %d\n", info->si_value.sival_int);
    }
    
    int main() {
        struct sigaction sa;
        memset(&sa, 0, sizeof(sa));
        sa.sa_sigaction = handler;
        sigemptyset(&sa.sa_mask);
        sa.sa_flags = SA_SIGINFO;
        if (sigaction(SIGUSR1, &sa, NULL) == -1) {
            perror("sigaction");
            exit(EXIT_FAILURE);
        }
        printf("My PID: %d\n", getpid());
        printf("Waiting for signal...\n");
        while (1) {
            pause();
        }
        return 0;
    }
    

    信号处理的最佳实践

    1. 保持信号处理函数简单:信号处理函数应尽可能简单,避免调用非异步信号安全的函数。
    2. 正确处理可重入性:确保在信号处理函数中只使用异步信号安全的函数。
    3. 使用 volatile sig_atomic_t:对于需要在信号处理函数和主程序之间共享的变量,应使用 volatile sig_atomic_t 类型。
    4. 考虑信号排队:注意大多数信号不会排队,连续发送的相同信号可能会被合并。
    5. 正确处理 EINTR:即使使用 SA_RESTART,某些系统调用仍可能被中断,需要适当处理。

    常见问题与解决方案

    1. 系统调用被信号中断

    解决方案:设置 SA_RESTART 标志或手动重启系统调用。

    sa.sa_flags = SA_RESTART; // 自动重启被中断的系统调用
    

    2. 信号处理函数中调用不可重入函数

    解决方案:仅使用异步信号安全的函数,或通过设置标志在主程序中执行复杂操作。

    3. 信号丢失

    解决方案:使用实时信号(SIGRTMIN 到 SIGRTMAX)并设置 SA_SIGINFO 标志,这些信号支持排队。

    与 signal() 函数的比较

    特性signal()sigaction()
    可移植性差好
    信号屏蔽控制无有
    附加信号信息无有
    系统调用重启控制无有
    处理函数重置行为不一致可控

    结论

    sigaction() 函数是 Linux 系统编程中处理信号的强大工具,它提供了比传统 signal() 函数更丰富、更可靠的功能特性。通过合理使用 sigaction(),开发者可以构建更健壮、更可靠的应用程序,有效处理各种异步事件。掌握 sigaction() 的使用是成为熟练 Linux 系统程序员的重要一步。

    在实际开发中,建议始终使用 sigaction() 而非 signal(),除非有特别简单的需求且可移植性不是考虑因素。通过 sigaction() 提供的丰富选项,可以应对各种复杂的信号处理场景。

  • Linux 进程核心解析:从 fork 开始理解程序运行
  • Linux 进程等待与程序替换详解:僵尸进程防治及 exec 实战
  • Linux 核心 IO 模型深析:CMake 构建与 Poll 多路转接实现
  • 网络编程核心:路由表、MTU/MSS、ARP、NAT 及代理技术解析
  • Linux 系统编程:深入理解一切皆文件与缓冲区原理及实战封装
  • Docker 入门:容器虚拟化基础与 Namespace 空间隔离
  • 2023 年全国职业院校技能大赛网络建设与运维赛项样题解析
  • Open WebUI MCPo 技术解析:MCP 协议转 OpenAPI 代理服务器
  • Qwen3 与 Qwen Agent 智能体开发实战:接入 MCP 工具
  • Python 实现 MCP 客户端调用高德地图天气查询示例
  • Dify MCP Server 插件:将工作流发布为第三方可调用服务
  • 基于 FastAPI 自动构建 SSE MCP 服务器
  • MCP Server 实现 Excel 表格一键生成可视化图表 HTML 报告