简述:Linux进程间通信--信号

Linux进程间通信之信号

简 介 : 简介: :

 信号机制是进程之间相互传递消息的一种方法,信号全称为软中断信号,用来通知进程发生了异步事件。进程之间可以互相通过系统调用kill发送软中断信号;内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件。

 收到信号的进程对各种信号有不同的处理方法。处理方法可以分为三类:
 1. 类似中断的处理程序,对于需要处理的信号,进程可以指定处理函数,由该函数来处理。
 2. 忽略某个信号,对该信号不做任何处理,就象未发生过一样。
 3. 对该信号的处理保留系统的默认值,这种缺省操作,对大部分的信号的缺省操作是使得进程终止。

信 号 的 基 本 术 语 信号的基本术语

  • 实际执行信号的处理动作称为信号递达(Delivery)
  • 信号从产生到递达之间的状态,称为信号未决(Pending)。
  • 进程可以选择阻塞 (Block )某个信号。
  • 被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作.

进 程 的 生 命 周 期 进程的生命周期

当向目标进程发送一枚信号SIGXXX时,Linux内核收到了产生的信号,然后再目标进程的进程描述符里记录了一笔:收到了信号SIGXXX,但是还没有递送给目标进程的这一段时间里,信号处于挂起状态,被称为 未 决 信 号 未决信号 。内核将信号递送给进程,进程就会暂停当前的控制流,转而去执行信号处理函数,这就是一个信号的完整生命周期。

信 号 的 分 类 信号的分类

不可靠信号:信号值在[1,31]之间的所有信号,被称为不可靠信号;也称非实时信号。对于不可靠信号,内核不一定能递送给目标进程,信号可能会丢失。
可靠信号:在[SIGRTMIN, SIGRTMAX]之间的信号被称为可靠信号;也称为实时信号。可靠信号时为了解决不可靠信号的丢失问题而产生的,Linux内核保证可靠信号能够递送给目标进程而不会丢失。

不同类型信号的特性:

  1. 对于不可靠信号,内核用位图(即进程表表现中的一个软中断信号域,该域中每一位对应一个信号)来记录该信号是否处于挂起状态。如果收到某不可靠信号,内核发现已经存在该信号处于未决状态,就会简单地丢弃该信号。因此发送不可靠信号,信号可能会丢失,即内核递送给目标进程的次数,可能小于信号发送的次数。

  2. 对于可靠信号,内核内部有队列来维护,如果收到可靠信号,内核会将信号挂到相应的队列中,因此不会丢弃。严格说来,内核也设有上限,挂起信号的个数也不能无限制地增大,不然耗费内核资源,因此只能说,在一定范围之内,可靠信号不会被丢弃。

简单来说就是:不可靠信号在递达之前产生多次只计⼀次,而可靠信号在递达之前产生多次可以依次放在一个队列⾥

L i n u x 对 不 可 靠 信 号 的 具 体 实 现 Linux对不可靠信号的具体实现 Linux

 对于不可靠信号(非实时信号),每个信号都有两个标志位分别表示阻塞(block)和未决(pending),还有一个函数指针表示处理动作。

 每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。因此,未决和阻塞标志可以用相同的数据类型sigset_t 来存储 ,sigset_t称为信号集。

这个类型可以表示每个信号的“有效”或“无效”状态,在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态.

sigsett 类型对于每种信号用一个 bit 表示 “ 有效 ” 或 “ 无效 ” 状态 , 至于这个类型内部如何存储这些 bit 则依赖于操作系统实现。

注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作

还 有 一 点 需 要 留 意 的 是 : 还有一点需要留意的是: 主控制流和信号响应函数使用不同的堆栈空间,它们之间不存在调用和被调用的关系,是两个独立的控制流程


相关函数:

  1. signal函数
#include <signal.h>
void (*signal(int signum, void (*handler)(int)))(int); 

typedef void (*sighandler_t)(int); 
sighandler_t signal(int signum, sighandler_t handler);
  1. kill函数
#include <sys/types.h> 
#include <signal.h>
int kill(pid_t pid, int sig); 

用来向任何进程或进程组发送任何信号
pid > 0:将信号sig发送到进程号为pid的进程
pid = 0:信号sig将发送给当前进程所属进程组里的所有进程
pid = -1:信号sig将发送给除了进程1和自身以外的所有进程
pid < -1:信号sig将发送给属于进程组-pid的所有进程

如果参数sig为0,将不发送信号

  1. pause函数
#include <unistd.h>
int pause(void); 

pause函数使进程进入睡眠,直到收到一个信号
该调用总是返回-1,并设置错误代码为EINTR(接收到一个信号)

如果信号的处理动作是终止进程,则进程终止,pause函数没有机会返回;如果信号的处理动作是忽略,则进程继续处于挂起状态,pause不返回;如果信号的处理动作是捕捉,则调用了信号处理函数之后pause返回-1,errno设置为EINTR, 所以pause只有出错的返回值。错误码EINTR表示“被信号中断”

  1. alarm函数
#include <unistd.h>
unsigned int alarm(unsigned int seconds); 

功能是设置一个定时器,当定时器计时到达时,将发出一个信号给进程

alarm安排内核为调用进程在指定的seconds秒后发出一个SIGALRM的信号

alarm后一次设定将取消前一次的设定

注意:alarm只设定为发送一次信号,如果要多次发送,就要多次使用alarm调用

  1. setitimer/getitimer函数
#include <sys/time.h> 
int getitimer(int which, struct itimerval *value); 
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue); 

setitimer用于设置定时器,getitimer用于获取定时器状态
该系统调用给进程提供了三个定时器,它们各自有其独有的计时域,当其中任何一个到达,就发送一个相应的信号给进程,并使得计时器重新开始
三个计时器由参数which指定:

TIMER_REAL:实际时间,计时到达发送SIGALRM信号
TIMER_VIRTUAL:进程执行时才计时,计时到达发送SIGVTALRM
TIMER_PROF:

  1. raise函数
  #include <signal.h>
  int raise( int signal );

raise函数用于给自己发送信号

未完。。。

参考:

  1. 《Linux环境编程 从应用到内核》高峰,李彬
  2. man signal
  3. 《UNIX网络编程 卷2:进程间通信》
  4. Linux信号 一 信号可靠性与分类
  5. 《UNIX环境高级编程》
  6. linux信号集

猜你喜欢

转载自blog.csdn.net/weixin_41629848/article/details/98867267
今日推荐