linux c编程:信号(四) sigaction
signal 函数的使用方法简单,但并不属于 POSIX 标准,在各类 UNIX 平台上的实现不尽相同,因此其用途受到了一定的限制。而 POSIX 标准定义的信号处理接口是 sigaction 函数,其接口头文件及原型如下:
#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
◆ signum:要操作的信号。
◆ act:要设置的对信号的新处理方式。
◆ oldact:原来对信号的处理方式。
◆ 返回值:0 表示成功,-1 表示有错误发生。
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:是一个函数指针,其含义与 signal 函数中的信号处理函数类似
sa_sigaction:另一个信号处理函数,它有三个参数,可以获得关于信号的更详细的信息。当 sa_flags 成员的值包含了 SA_SIGINFO 标志时,系统将使用 sa_sigaction 函数作为信号处理函数,否则使用 sa_handler 作为信号处理函数。
sa_flags 成员用于指定信号处理的行为,它可以是一下值的“按位或”组合。
◆ SA_RESTART:使被信号打断的系统调用自动重新发起。
◆ SA_NOCLDSTOP:使父进程在它的子进程暂停或继续运行时不会收到 SIGCHLD 信号。
◆ SA_NOCLDWAIT:使父进程在它的子进程退出时不会收到 SIGCHLD 信号,这时子进程如果退出也不会成为僵尸进程。
◆ SA_NODEFER:使对信号的屏蔽无效,即在信号处理函数执行期间仍能发出这个信号。
◆ SA_RESETHAND:信号处理之后重新设置为默认的处理方式。
◆ SA_SIGINFO:使用 sa_sigaction 成员而不是 sa_handler 作为信号处理函数
sa_mask: 这个参数指明了在信号处理函数执行过程中应该被阻止的信号的mask值。此外,触发这个handler的信号应该被阻止。
首先来看下sigaction的用法:
void ouch(int signum){
printf("received sig=%d\n",signum);
}
void signal_action_fun(){
struct sigaction act;
act.sa_handler=ouch;
sigemptyset(&act.sa_mask);
act.sa_flags=0;
sigaction(SIGINT,&act,NULL);
while(1){
printf("hello world!\n");
sleep(1);
}
}
当接受到终端发送的CTRL_C信号的时候,将会打印出该信号的值
继续来看下使用sa_sigaction的用法。
sa_sigaction函数中的siginfo_t 参数是一个如下定义的结构体:从中可以获取信号编号,进程ID等等信息
siginfo_t {
int si_signo; /*信号编号*/
int si_errno; /*错误号*/
int si_code; /*信号码*/
int si_trapno;/*导致硬件产生信号的trap号*/
pid_t si_pid; /*发送进程ID*/
uid_t si_uid; /*发送进程真实的用户ID*/
int si_status; /*退出值*/
clock_t si_utime; /*花费的用户时间*/
clock_t si_stime; /*花费的系统时间*/
sigval_t si_value; /*信号值*/
int si_int ; /*POSIX.1b 信号*/
void *si_ptr; /*POSIX.1b 信号*/
int si_overrun
int si_timerid
void *si_addr
long si_band
int si_fd;
short si_addr_lsb;
}
代码修改如下:
void ouch(int signum,siginfo_t *info,void *para){
printf("received sig=%d,the process id is %d\n",signum,info->si_pid);
printf("the uid is %d\n",info->si_uid);
}
void signal_action_fun(){
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_flags=0;
act.sa_flags|=SA_SIGINFO; /*设置SA_SIGINFO表示使用sa_sigaction*/
act.sa_sigaction=ouch;
sigaction(SIGINT,&act,NULL);
while(1){
printf("hello world!\n");
sleep(1);
}
}
运行结果如下:在收到CTRL_C信号后,会打印出信号ID,进程ID以及用户ID。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架