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

进程信号之sigaction系统调用

目录

信号捕捉的大致逻辑

函数原型

函数作用

参数说明

返回值

struct sigaction 结构体

信号集函数

示例代码

被挂起的信号


信号捕捉的大致逻辑

        建议大家先看一下这篇文章进程信号之signal系统调用-CSDN博客,通过简单学习一下signal来了解信号捕捉,然后自定义处理函数的大致逻辑。

函数原型

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

函数作用

  sigaction 是一个设置信号处理方式的系统调用,它比传统的 signal 函数提供了更强大和灵活的信号处理机制。

参数说明

  • signum:指定要设置处理方式的信号编号。常见的信号如 SIGINT(中断信号,通常由 Ctrl + C 产生)、SIGTERM(终止信号)、SIGKILL(杀死信号,不可被捕获或忽略)等。
  • act:一个指向 struct sigaction 结构体的指针,用于指定新的信号处理方式。如果设置为 NULL,则恢复该信号的默认处理方式。
  • oldact:也是一个指向 struct sigaction 结构体的指针,用于保存旧的信号处理方式。如果不需要保存旧的处理方式,可以将其设置为 NULL

返回值

  sigaction 函数成功时返回 0,失败时返回 -1,并设置 errno 以指示错误原因。常见的错误包括无效的信号编号、权限不足等。

struct 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);
};
  • sa_handler:这是一个函数指针,指向信号处理函数。该函数只有一个整数参数,即接收到的信号编号。
  • sa_sigaction:另一个函数指针,指向更复杂的信号处理函数。它可以获取关于信号的更多信息,比如信号发送者的进程 ID 等。该函数有三个参数:接收到的信号编号、指向 siginfo_t 结构体的指针(包含信号的详细信息)和一个指向 void 的指针(通常用于传递上下文信息)。当 sa_flags 中设置了 SA_SIGINFO 标志时,会使用这个函数来处理信号。
  • sa_mask一个信号集,用于指定在执行信号处理函数期间要阻塞的信号。例如,如果在处理 SIGINT 信号时,希望阻塞 SIGTERM 信号,可以将 SIGTERM 添加到 sa_mask 中。在信号处理函数开始执行前,sa_mask 中的信号会被自动阻塞,处理函数执行完毕后,这些信号的阻塞状态会被恢复到之前的状态。
  • sa_flags:一些标志位,用于指定信号处理的行为。常见的标志有:
    • SA_RESTART:如果信号中断了系统调用(如 readwritewait 等),设置此标志后,系统调用会自动重启,而不是返回 -1 并将 errno 设置为 EINTR。例如,一个正在读取文件的 read 系统调用被信号中断,如果设置了 SA_RESTARTread 会自动重新开始读取,而不会让应用程序认为读取操作失败。
    • SA_SIGINFO:表示使用 sa_sigaction 函数而不是 sa_handler 函数来处理信号,以便获取更详细的信号信息。
    • SA_NODEFER:默认情况下,在执行信号处理函数期间,该信号会被自动阻塞,防止递归调用信号处理函数。设置 SA_NODEFER 标志后,在处理该信号时,不会阻塞该信号本身,这可能会导致信号处理函数被递归调用,需谨慎使用。
  • sa_restorer:此成员已过时,在现代系统中不再使用,通常设为 NULL

信号集函数

        前面提到Linux用数据结构sigset_t表示一组信号集,处在信号集中的信号,在执行sigaction捕捉的信号的对应自定义捕捉函数时,会阻塞。下列是对信号集的各种操作方法:

  • int sigemptyset(sigset_t *set);清空一个信号集,即把信号集中所有信号都设置为未包含状态。成功时返回 0,失败时返回 -1
  • int sigfillset(sigset_t *set);将信号集中所有信号都设置为包含状态,即填充信号集。成功时返回 0,失败时返回 -1
  • int sigaddset(sigset_t *set, int signum);将指定的信号 signum 添加到信号集 set 中。成功时返回 0,失败时返回 -1
  • int sigdelset(sigset_t *set, int signum);从信号集 set 中移除指定的信号 signum。成功时返回 0,失败时返回 -1
  • int sigismember(const sigset_t *set, int signum);检查指定的信号 signum 是否在信号集 set 中。如果信号 signum 在信号集 set 中,返回 1;如果不在,返回 0;如果出错(如无效的信号集指针),返回 -1

示例代码

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

被挂起的信号

        在执行sigaction设置的特定信号的处理函数期间,如果sigaction在为这个特定信号设置处理函数时设置阻塞了一些信号,那么这个被阻塞的信号如果在自定义函数执行期间产生了,则被挂起,当这个自定义函数执行完毕,这个被挂起的信号会被重新发给进程。

        举个例子
 

#include <stdio.h>
#include <signal.h>
#include <unistd.h>void my_handler(int signum) {printf("Received signal %d\n", signum);
}int main() {struct sigaction act;act.sa_handler = my_handler;sigemptyset(&act.sa_mask);sigaddset(&act.sa_mask, SIGTERM);//阻塞SIGTERM信号act.sa_flags = 0;if (sigaction(SIGINT, &act, NULL) == -1) {perror("sigaction");return 1;}printf("Waiting for signal...\n");while (1) {sleep(1);}return 0;
}
  • 当用户按下 Ctrl + C 触发 SIGINT 信号,进入 sigint_handler 处理函数,此时如果尝试发送 SIGTERM 信号(例如通过另一个终端执行 kill -SIGTERM <pid><pid> 为该进程的 ID),SIGTERM 信号会被挂起。
  • 当 sigint_handler 处理函数执行完毕,由于 SIGTERM 信号仍然处于挂起状态且系统默认 SIGTERM 的处理方式是终止进程,所以进程会终止,即 SIGTERM 信号在 sigaction 处理函数结束后被执行。

        在本文所讲解的知识大家都已经理解的基础上,请大家务必阅读进程的信号掩码,信号集,sigprocmask函数-CSDN博客,从而更加立体的理解信号捕捉。

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

相关文章:

  • 【技术支持】Android11 中获取应用列表
  • 商城系统源码加密与不加密(开源)的区别
  • JavaEE-Maven
  • 多线程应用
  • Project Reactor响应式编程简介
  • 初识 Redis:从入门到应用的全面指南
  • 数字化动态ID随机水印和ID跑马灯实现教育视频防录屏
  • 数据治理域——离线数据开发
  • Codeforces 2025/6/11 日志
  • 项目练习:使用mybatis的foreach标签,实现union all的拼接语句
  • Nacos快速入门:从安装到实战
  • MySQL 8.0 OCP 英文题库解析(十七)
  • 打砖块(洛谷)
  • 移动端 1px 问题解决方案
  • 从字节到对象的漂流---JavaIO流篇
  • 5. 相机拍摄简单构图
  • 1.9 Express
  • Flutter 常用组件详解:Text、Button、Image、ListView 和 GridView
  • c++中main函数执行完后还执行其它语句吗?
  • FreeRTOS互斥量
  • 面向异构系统的多面体编译优化关键技术研究——李颖颖博士
  • Linux 任务调度策略
  • 一数一源一标准的补充
  • 论文阅读:强化预训练
  • 强化学习入门:交叉熵方法实现CartPole智能体
  • 一个超强的推理增强大模型,开源了,本地部署
  • 跨网数据摆渡系统:破解数据流通难题的“标准答案”
  • 别人如何访问我的内网呢? 设置让外网访问内网本地服务器和指定端口应用的几种方式
  • 曼昆《经济学原理》第九版 第十八章生产要素市场
  • Vue Electron 使用来给若依系统打包成exe程序,出现登录成功但是不跳转页面(已解决)