APUE--信号(4)

signal()有个高级版本的函数sigaction(),这个函数功能上要比signal()强大且具有可移植性

[cpp]  view plain copy
  1. int sigaction(int signum, const struct  sigaction *act, struct sigaction *oldact);  
第一个参数signum信号编号,第二个参数和第三个参数分别是入参和出参,是注册的信号处理动作,那来看下struct sigaction结构:

[cpp]  view plain copy
  1. struct sigactgion {  
  2.       void (*sa_handler)(int);     //信号捕捉函数,同signal(可以是SIG_IGN SIG_DFL)  
  3.       sigset_t sa_mask;               
  4.       int sa_flags;      
  5.       void (*sa_sigaction)(int , siginfo_t *, void *);  
  6. };  
首先要来看第一个成员sa_handler和最后一个成员sa_sigaction,都是函数指针(并且这两个函数指针实际上是共用体,是不同的处理函数函数版本),sa_handler注册的处理函数类型和signal()函数的注册的一样;第二个成员sa_mask是信号处理函数执行过程中增加的屏蔽字,默认情况下只是将当前信号增加到屏蔽字中,可以手动增加,在执行时增加执行结束后解除;第三个参数sa_flags是一些特殊的选项,来看下都有哪些选项是常用的:

SA_INTERRUPT和SA_RESTART两个选项只能有一个,前者是被打断的系统调用不会启动重启后者会自动重启,比如read()在阻塞时如果到来一个信号read()会被打断,如果信号的处理动作中设置SA_RESTART会自动重启,如果设置了SA_INTRRUPUT则不会自动重启,read()返回-1并设置errno为EINTR。(默认是SA_RESTART 忽略的信号不能打断低速系统调用)。

SA_NOCLDWAIT,用户SIGCHLD信号,子进程不会创建僵尸进程。SA_SIGINFO,设置了则使用高级版本的信号处理函数sa_sigaction。

SA_NODEFER,在该信号的处理函数中不会阻塞该信号,用于不可靠信号。

最后在来看看高级版本的信号处理函数sa_sigaction,该函数指针指向的处理函数的第一个参数仍然是信号编号,第二个参数是一个结构体指针,该结构体中提供了信号产生原因的一系列信息,最后一个参数void*是一个上下文环境,用不到。来看下siginfo_t结构

[cpp]  view plain copy
  1. struct siginfo_t {  
  2.        int      si_signo;       /* Signal number */  
  3.        int      si_errno;       /* if nonzero, errno value from errno.h */  
  4.        int      si_code;        /* additional info(depends on signal) 详细见下图 */  
  5.        pid_t  si_pid;         /* Sending process ID */  
  6.        uid_t  si_uid;         /* Real user ID of sending process */  
  7.        void*  si_addr;       /*  adress that caused the fault   */  
  8.        int      si_status;      /* Exit value or signal number */  
  9.        int      si_band;        /* Band number for SIGPOLL */  
  10.        sigval_t     si_value;       /*  信号伴随的额外信息 */  
  11.        /* possibly other fields also */  
  12. ;  
这些成员中,需要掌握的包括si_signo信号编号 si_code记录了信号产生的原因(如SIGSEGV信号当si_code为SI_USER使用kill函数或kill命令发送的 SEGV_ACCER段错误)

si_pid si_uid是发送者的信息,但只针对SIGCHLD和可靠信号有效。从si_value中可以获得发送信号时携带的信息,类型是sigval_t,其实是一个共用体,如下

[cpp]  view plain copy
  1. union sigval {  
  2.      int   sival_int;  
  3.      void *sival_ptr;  
  4. };  
union sigval和sigval_t是一样的类型,可以看出信号携带的数据可以是一个整型数或者一个地址(当然不同进程间的地址一般是没有任何意义的)。

那如何在发送时发送携带数据?使用sigqueue()函数发送信号时可以携带数据:

[cpp]  view plain copy
  1. int sigqueue(pid_t pid, int sig,  const  union sigval value);  
前两个参数不用多说,随后一个参数就是携带数据共用体,这样一来,通过信号就能实现一个简单的进程间通信了。

最后我们说明一下实时信号的概念,在常用的前一部分非实时信号后,SIGRTMIN~SIGRTMAX这些信号是实时信号。

信号(1)中我们提到,当在不可靠信号处理函数执行过程中,再次接受到多个相同的信号,则当处理函数执行完毕后只再执行一般,其余的信号丢失了,也就是当不可靠信号处于阻塞状态下,最多只能有个该信号处于未决状态,其余的都丢失了;实时信号不会丢失,实现了排队的功能,并且实时信号时用户优先级的,优先级是由SIGRTMIN~SIGRTMAX依次递增的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值