Unix环境高级编程读书笔记(8)

*、信号提供了一种处理异步事件的方法,例如终端用户键入中断键,会通过信号机制停止一个程序,或及早终止管道中的下一个程序
*、每个信号都有一个名字,这些名字都以3个字符SIG开头,例如SIGABRT是夭折信号,当进程调用abort函数时产生这种信号,SIGALRM是闹钟信号,由alarm函数设置的定时器超时后将产生此信号
*、信号是异步事件的经典实例,产生信号的事件对进程而言是随机出现的,进程不能简单地测试是一个变量来判断是否发生了一个信号,而是必须告诉内核“在此信号发生时,请执行下列操作”
*、在某个信号出现时,可以告诉内核按下列3种方式之一进行处理
1)忽略此信号,大多数信号都可以使用这种方式进行处理,但有两种信号坚决不能被忽略。它们是SIGKILL和SIGSTOP。这两种信号不能被忽略的原因是:它们向内核和超级用户提供了使进程终止或停止的可靠方法。另外,如果忽略某些由硬件异常产生的信号,则进程的运行行为是未定义的。
2)捕获信号:要通知内核在某种信号发生时,调用一个用户函数,如果捕捉到SIGCHLD信号,则表示一个子进程已经终止,所以此信号的捕捉函数可以调用wait/waitpid已取得该子进程的进程ID以及它的终止状态,注意:不能捕捉SIGKILL和SIGSTOP信号
3)执行系统默认动作:注意:大多数信号的系统默认动作是终止该进程
*、常见信号的名字
SIGABRT:调用abort函数时产生此信号。进程异常终止;
SIGALRM:调用alarm函数设置的定时器超时,产生此信号
SIGBUS:当出现某些类型的内存故障时,常常产生此种信号
SIGCHLD:在一个进程终止或者停止时,SIGCHLD信号被送给其父进程。按系统默认,将忽略此信号。如果父进程希望被告知其子进程的这种状态改变,则应捕捉此信号。信号捕捉函数中通常要调用一种wait函数以取得子进程ID和其终止状态
SIGCONT:此作业控制信号发送给需要继续运行,但当前处于停止状态的进程
SIGFPE:此信号表示一个算术运算异常,如除以0
SIGHUP:如果终端接口检测到一个连接断开,则将此信号送给与该终端相关的控制进程
SIGILL:此信号表示进程已执行一条非法硬件指令
SIGINT:当用户按中断键时,终端驱动程序产生此信号并发送至前台进程组中的每一个进程
SIGPIPE:如果在管道的读进程已终止时写管道,则产生此信号。当类型为SOCK_STREAM的套接字已不再连接时,进程写该套接字也产生此信号
SIGQUIT:当用户在终端上按退出键时,中断驱动程序产生此信号
SIGSEGV:指示进程进行了一次无效的内存引用
SIGSTOP:它停止一个i进程
*、void (*signal(int signo,void(*func)(int)))(int);
//signo参数是信号名,func的值是常量SIG_IGN、常量SIG_DFL或当接到此信号后要调用的函数的地址
//返回值是指向在此之前的信号处理程序的指针
*、可以用来将一个信号发送给一个进程
*、低速系统调用是可能会使进程永远阻塞的一类系统调用,在这些低速系统调用中,一个值得注意的例外是于磁盘I/O有关的系统调用,虽然读写一个磁盘可能暂时阻塞调用者,但是除非发生硬件错误,I/O操作总会很快返回,并使调用者不再处于阻塞状态;系统调用被中断后就会出错返回,但对有的系统调用实现了重启功能
*、可重入函数:即异步信号安全的函数,比如在执行malloc函数时,引发了信号处理程序,会对进程造成破坏,因为malloc是用链表来维护的,可能在调用信号处理函数的时候正在改变此链表,但是在信号处理函数中可能又调用Malloc,从而破坏了这种状态
*、信号发生的四种情形:1、硬件异常2、软件异常3、由终端引发的信号4、调用kill函数引发的信号
*、当一个信号产生时,内核通常在进程表中以某种形式设置一个标志,当对信号采取这种动作时,我们说向进程递送了一个信号,在信号产生和递送之间的时间间隔内,称信号是未决的。进程可以选用“阻塞信号传递”,并且对该信号的动作是系统默认或者捕捉该信号,则为该进程将此信号保持为未决状态,进程调用sigpending来判定哪些信号是设置为阻塞并处于未决状态,如果在进程解除对某个信号的阻塞之前,这种信号发生了多次,则只递送这种信号一次。
*、每个进程都有一个信号屏蔽字,它规定了当前要阻塞递送到该进程的信号集
*、编号为0的信号定义为空信号,如果signo参数是0,这常被用来确定一个特定的进程是否仍然存在
*、sigprocmask:一个进程的信号屏蔽字规定了当前阻塞而不能递送给该进程的信号集,sigpromask函数就和信号屏蔽字有关
*、sigpending:返回阻塞的处于未决状态的信号集
*、sigaction:检查或者修改与指定信号相关联的处理动作


1、信号是一种软中断,可以由以下情形触发:
1)用户按下某些终端键,例如ctrl+d
2)硬件异常,例如除数为0,无效的内存引用
3)kill
4)当软条件达成,且有进程需要得到此通知


当信号发生时,可以告诉内核进行以下处
1)忽略信号:有两个信号不能被忽略:SIGKILL,SIGSTOP,不能被忽略的原因是这两个信号为内核和超级用户提供了一条可靠的方法去杀死和暂停进程。当忽略一些来自硬件的异常信号,产生的结果是未定义的
2)捕获信号:在捕获信号之前,首先要定义捕获信号之后如何处理,SIGKILL和SIGSTOP信号不能被捕获
3)默认处理信号:每一个信号都有一个默认的处理,大部分处理方式都是终止进程,如果想看各个处理方式,可以在终端输入man 7 signal


2、#include <signal.h>
void (*signal(int sig,void(*func)(int)))(int);


这个signal函数接收两个参数
参数1:信号编码,如:SIGCHLD等
参数2:接收信号处理函数指针,函数原型void func(int);


还有三个定义:
#define SIG_ERR (void(*)())-1 //返回错误值
#define SIG_DFL (void(*)())0 //忽略参数1所指信号
#define SIG_IGN (void(*)())1 //恢复为参数1所指信号的处理方法为默认方法
可以作为参数2或者signal的返回值


3、
1)当执行一个程序时,所有信号的状态都是系统默认或者忽略,且信号响应后执行默认动作,直到在程序中做出改变;
2)当使用fork后,子进程继承父进程的信号处理方式;
3)当fork后又使用exec,新的程序中的信号又恢复了默认,因为替换旧的数据空间、堆、栈等,使得原来处理函数对于新的程序来说,已经失效。




4、int sigempty(sigset_t *set);//将set清空
int sigfillset(sigset_t *set);//将所有的信号填充到set
int sigaddset(sigset_t *set,int signum);//添加指定信号signum到set中
int sigdelset(sigset_t *set,int signum);//从set中移除指定信号signum
int sigismember(sigset_t *set,int signum);///signum是否是set中的成员


5、sigprocmask


int pthread_sigmask(int how,const sigset_t *set,sigset_t *oset);
int sigprocmask(int how,const sigset_t *set,sigset_t *oset);


sigprocmask:用于设定信号屏蔽集内信号的处理方式
SIG_BLOCK:set中包含了我们所希望添加的阻塞信号
SIG_UNBLOCK:set中包含了我们所希望解除阻塞的信号
SIG_SETMASK:setz为我们所设置屏蔽的信号


6、int sigpending(sigset_t *set);


sigpending:通过set返回已经通知进程,但被阻塞而挂起的信号,比如阻塞了SIGINT信号一段时间,而在这段时间中产生了这个信号阿,通知进程,这个信号称之为
pending信号。如果产生多个SIGINT信号,在Linux实现中,也只会处理一次。


7、int sigaction(int sig,const struct sigaction*act,struct sigaction*oact);指定或者修改与指定信号相关联的处理动作

猜你喜欢

转载自blog.csdn.net/metheir/article/details/70211244
今日推荐