2016-02-17
alarm 和 pause函数
使用alarm函数可以设置一个时间值,在将来的某个时刻该时间值会被超过。产生SIGALRM信号。如果不忽略或不捕捉此信号,则其默认动作是终止该进程。
#include
unsigned int alarm(unsigned int seconds) //seconds单位为秒
每个进程只能有一个脑中时间。如果在调用alarm时,以前已经为该进程设置过闹钟时间,而且此闹钟没有超时,则该闹钟时间的剩余值作为本次alarm的返回值。以前登记的闹钟时间被新值所取代。
pause函数使调用进程挂起直到捕捉到一个信号。
#include
int pause(void);
只有执行了一个信号处理程序并从其返回pause才返回。这种情况下pause返回-1 errno设置为EINTR
信号集
我们需要有一个能表示多个信号(信号集)的数据类型。将在sigprocmask这样的函数中使用这种数据类型。以告诉内核不允许发生该信号集中的信号。如前所述信号种类数目有可能超过一个整形来那个所包含的位数,所以一般而言不能用整型量中的一位代表一种信号。POSIX定义数据类型sigset_t以包含一个信号集,并且定义了5个处理信号集的函数。
#include
int sigemptyset (sigset_t *set)
int sigfillset(sigset_t *set)
int sigaddset(sigset_t *set, int signo)
int sigdelset(sigset_t *set, int signo) //四个函数若成功返回0,出错返回-1
int sigismenber(const sigset_t *set, int signo)
函数sigemptyset初始化由set指向的信号集,使排除其中的说由信号。函数sigfillset初始化由set指向的信号集,使其包括所有的信号。所有应用程序在使用信号集前,要对该信号集调用sigemptyset或者sigfillset初始化。这是因为c编译程序将不赋初值的外部和静态变量都初始化为0,而这是否与给定系统上信号集的实现相对应并不清楚。
一旦已经初始化了一个信号集,以后就可在该信号集中增删特定的信号。函数sigaddset将一个信号添加到现存信号集中,sigdelset则从信号集中删除一个信号。
sigprocmask函数
一个进程的信号屏蔽字规定了当前阻塞而不能传递给该进程的信号集。调用函数sigprocmask可以检测或者更改进程的信号屏蔽字。
int sigptocmask(int how, const sigset_t *set, sigset_t *oset)
首先oset是非空指针,该进程的当前信号屏蔽字通过oset返回。其次若set是一个非空指针,则参数how指示如何修改当前信号屏蔽字。how的取值如下:
- SIG_BLOCK 该进程新的信号屏蔽字是当前信号屏蔽字和set的并集
- SIG_UNBLOCK set包含了我们希望解除阻塞的信号
- SIG_SETMASK 该进程新的信号屏蔽字是set指向的值
如果set是个空指针,则不改变该进程的信号屏蔽字,how的值也就无意义了
如果在调用sigprocmask后有任何未决的不再阻塞的信号,则在sigprocmask返回前,至少将此信号递送给该进程一次(如果系统不支持信号排队)。
sigpending函数
sigpending返回对于调用进程被阻塞不能递送和当前未决的信号集。该信号集通过set参数返回
int sigpending(sigset_t *set)
sigaction函数
sigaction函数是检查或者修改与指定信号相关联的处理动作。
int sigaction(int signo, const struct sigaction *act, struct sigaction *oact)
其中,参数signo是要检查或者修改信号的编号。若act指针非空,则要修改其动作。如果oact指针非空,则系统返回该信号的原先动作。
struct sigaction {
void (*sa_handler)();
sigset_t sa_mask;
int sa_flags;
}
当更改信号动作时,如果sa_handler指向一个信号捕捉函数则sa_mask字段说明了一个信号集,在调用信号捕捉函数之前,该信号集要加到进程的信号屏蔽字中。仅当从信号捕捉函数返回时再将进程的信号屏蔽字恢复为原先值。这样,在调用信号处理程序时就能阻塞某些信号。在信号处理程序被调用时,系统建立的新的信号屏蔽字会自动包括正在被递送的信号。因此保证了在处理一个给定的信号时,如果这种信号再次发生,那么它会被阻塞到对前一个信号处理结束为止。若同一个信号发生多次,通常它们并不排队,所以如果在某种信号被阻塞时它发生了五次,那么对这种信号解除阻塞后其信号处理函数通常只会被调用一次。
sigsetjmp和siglongjmp
在信号处理程序中经常调用longjmp函数以返回到程序的主循环中,而不是从该处理程序返回。调用longjmp时有一个问题,当捕捉到一个信号时,进入信号捕捉函数,此时当前信号被自动地加到进程的信号屏蔽字中。这阻止了后来产生的这种信号中断此信号处理程序。为了允许两种形式并存,POSIX并没有说明setjmp和longjmp对信号屏蔽字的作用,而是定义了两个新函数sigsetjmp和siglongjmp。在信号处理程序中作非局部转移时应当使用这两个函数。
int sigsetjmp(sigjmp_buf env, int savemask)
void siglongjmp(sigjmp_buf env, int val)
这两个函数和setjmp,longjmp之间的唯一区别是sigsetjmp增加了一个参数。如果savemask非0,则sigsetjmp在env中保存进程的当前信号屏蔽字。调用siglongjmp时,如果带非0savemask的sigsetjmp调用已保存了env则siglongjmp从其中恢复保存的信号屏蔽字。
sigsuspend函数
更改进程的信号屏蔽字可以阻塞或者解除阻塞所选择的信号。使用这种技术可以保护不希望由信号中断的代码临界区。如果希望对一个信号解除阻塞,然后pause以等待以前被阻塞的信号。如果在解除对信号的阻塞和pause之间发生了此信号,则信号将被丢失。为了纠正此问题,需要在一个原子操作中实现恢复信号屏蔽信号字,然后使进程睡眠,这种功能是由sigsuspend函数所提供的。