信号量与异步通知
一 信号量原理概述
1
LINUX当中的信号处理机制
进程管理块(PCB)中有几个字节的比特位,每一个比特位代表着一种信号。进程首先要注册一个函数用于处理对应的信号,一般来说调用signal或者是signalaction函数。当用kill指令向某一个进程发送信号,就会陷入内核,通过进程号(PID)取得对应得PCB,然后将PCB中对应信号得比特位置位。在内核返回用户空间之前,会进行PCB的信号比特位检查,检查有置位时,就调用前面注册得相对应得函数进行处理。
2
发送信号
使用kill指令发送信号时,必须给出的参数有PID。内核通过PID索引到PCB,然后将对应得比特位置位,即完成了信号的发送。一般来说,对于异步通知,信号的发送是驱动程序需要完成的任务。
3
信号屏蔽
每个进程都有一个信号集,用于描述哪些信号被屏蔽,这个信号集叫做信号掩码。信号屏蔽并非让进程不响应信号,只是延迟了信号的到达,只要屏蔽解除,信号响应会继续进行。
4
捕捉信号
进程对信号的响应就是捕捉到了信号。在进程初始化时,每一个信号都会被注册一个默认的处理函数。我们可以调用signal来注册自己的处理函数用于取代默认处理函数。这个signal也可以说是信号捕捉函数。捕捉信号是用户程序的任务,驱动程序不会干涉。
二 信号量操作
1
信号量的捕获
#include
typedef
void (*sighandler_t)(int)
signalhandler_t
signal(int signum, sighandler_t handler)
#include
int
sigaction(int signum, const struct sigaction *act,
struct
sigaction *oldact)
其中signum
表示要操作的信号量
act
是新的操作方式
oldact是旧的操作方式
struct
sigaction {
void
(*sa_handler)(int);
void
(*sa_action)(int, siginfo_t *,void *);
sigset_t
mask;
int
sa_flag;
void
(*sa_restorer)(void);
}
成员说明: sa_handler是信号量处理函数
sa_sigaction 用于获取信号量详细信息的函数
mask 用于信号处理函数期间屏蔽信号的信号掩码
sa_flag 用于控制信号处理行为的标志位
sa_restorer 已废弃,不使用
2
信号的发送
原理:在用户程序当中,调用了fasync函数时给出两个命令标志,分别为F_SETDOWM和F_SETFL(set
fasync
list),前者会调用f_setdown函数,该函数将当前进程的PID记录到file->f_owner当中去。后者调用会导致调用setfl函数,该函数调用到驱动程序当中得fasync函数,在fasync函数中会调用fasync_hlper函数,这个函数将当前进程加入到fasync链表当中去。当调用到kill_fasync
函数发送信号时,就会历遍这个链表,并且调用sed_sigio函数发送信号。(sed_sigio(fowm,fa->fa_fd,band))。