UNIX环境高级编程读书笔记(十)—信号 (4)

 

四、信号屏蔽字:

有时候我们希望进程正确的执行,而不想进程受到信号的影响,比如我们希望上面那个程序在1秒钟之后不结束。这个时候我们就要进行信号的操作了。

信号操作最常用的方法是信号屏蔽。信号屏蔽要用到下面的几个函数。

sigemptysetsigfillsetsigaddsetsigdelsetsigismembersigprocmask。下面对他们分别进行讲解。

 

8

名称:

sigemptyset/sigfillset/sigaddset/sigdelset/sigismember

功能

处理信号集

头文件

#include <signal.h>

函数原形:

int sigemptyset(sigset_t *set);

int sigfillset(sigset_t *set);

int sigaddset(sigset_t *set,int signum);

int sigdelset(sigset_t *set,int signum);

int sigismember(const sigset_t *set,int signum);

参数:

set 信号集

signum 信号

返回值:

若成功返回0,若出错返回-1

若真返回1,若假返回0,若出错返回-1 sigismember

      

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

我们需要有一个能表示多个信号—信号集的数据类型。我们将在诸如sigprocmask之类的函数中使用这种数据类型,以便告诉内核不允许发生该信号集中的信号。上面的5个函数可以对信号集进行处理。

函数sigemptyset 初始化由set指向的信号集,清除其中所有信号。函数sigfillset初始化由set指向的信号集,使其包含所有信号。所以信号在使用信号集前,要对信号集调用sigemptysetsigfillset一次。

函数sigaddset 将一个信号添加到现有集中,sigdelset则从信号集中删除一个信号。对所有以信号集作为参数的函数,我们总是以信号集地址作为其传送的参数。

       sigismember查询信号是否在信号集合之中。

下面的例子:

/*10_7.c*/

#include <stdio.h>

#include <signal.h>

 

main()

{

sigset_t *set;

set=(sigset_t*)malloc(sizeof(set));

 

sigemptyset(set);/*初始化信号集*/

sigaddset(set,SIGUSR1);/*添加信号SIGUSR1到信号集中*/

sigaddset(set,SIGINT);/*添加信号SIGUSR2到信号集中*/

 

if((sigismember(set,SIGUSR1))==1)/*测试信号SIGUSR1是否在信号集中*/

    printf(“SIGUSR1/n”);

if((sigismember(set,SIGUSR2))==1)

    printf(“SIGUSR2/n”);

if((sigismember(set,SIGINT))==1)

    printf(“SIGINT/n”);

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

下面是执行结果:

# ./10_7

SIGUSR1

SIGINT

程序先初始化信号集,清除其中所有信号,然后把SIGUSR1SIGINT添加到信号集中,然后测试SIGUSR1SIGUSR2SIGINT信号是否在信号集中。因为SIGUSR2不在信号集中,所以程序并不打印SIGUSR2

 

9

名称:

sigprocmask

功能

检测或更改信号屏蔽字

头文件

#include <signal.h>

函数原形

int sigprocmask(int how,const sigsett_t *set,sigset_t *oldset);

参数:

how  操作方式

set   信号集

oldest

返回值:

若成功返回0,若出错返回-1

 

 

 

 

 

 

 

 

 

 

 

 

每个进程都有一个用来描述哪些信号递送到进程时将被阻塞的信号集,该信号集中的所有信号在递送到进程后都将被阻塞。

sigprocmask是最为关键的一个函数。在使用之前要先设置好信号集合set。这个函数的作用是将指定的信号集合set加入到进程的信号阻塞集合之中去,如果提供了oldset那么当前的进程信号阻塞集合将会保存在oldset里面。参数how决定函数的操作方式。

SIG_BLOCK:增加一个信号集合到当前进程的阻塞集合之中。

SIG_UNBLOCK:从当前的阻塞集合之中删除一个信号集合。

SIG_SETMASK:将当前的信号集合设置为信号阻塞集合。

 

我们把10_7.c稍微修改一下,看看sigprocmask函数的功能。

/*10_8.c*/

#include <stdio.h>

#include <signal.h>

 

main()

{

sigset_t *set;

set=(sigset_t*)malloc(sizeof(set));

 

sigemptyset(set);/*定义信号集set*/

sigaddset(set,SIGINT);/*把信号SIGINT添加到信号集中*/

sigprocmask(SIG_SETMASK,set,NULL);/*set设置为信号阻塞集合*/

wile(1);/*死循环*/

}

程序先定义信号集set,然后把信号SIGINT添加到set信号集中,最后把set设置为信号阻塞集合。当我们运行程序时,进程进入死循环。我们按“ctrl+c”系统并没有中断程序,因为我们已经把SIGINT信号屏蔽掉了。我们可以按”ctrl+z”来结束程序。

sigeprocmask函数通常和sigemptyset/sigfillset/sigaddset/sigdelset/sigismember函数配合使用,主要有两种用途:

1.我们不希望某些不太重要的信号来影响我们的进程,我们就可以把这些信号添加到信号屏蔽集中。使它们不打扰进程的执行。

2.如果系统现在很忙,没有时间及时相应信号,进程可以先把信号阻塞掉,等系统有空闲时间在去相应,这也保证了信号的可靠性。下面的函数可以做到这一点。

 

10

名称:

sigpending

功能:

返回信号集

头文件:

#include <signal.h>

函数原形:

int sigpending(sigset_t *set);

参数:

 

返回值:

若成功返回0,若出错返回-1

 

 

 

 

 

 

 

 

 

我们要注意的是,阻塞信号并不是丢弃信号,它们被保存在一个进程的信号阻塞队列里,sigpending可以获得当前已递送到进程,却被阻塞的所有信号,在set指向的信号集中返回这些信号。

 

下面是一个例子:

/*10_9.c*/

#include <stdio.h>

#include <signal.h>

#include <stdlib.h>

 

int main(void)

{

sigset_t newmask,oldmask,pendmask;

 

sigemptyset(&newmask);  /*初始化信号集*/

sigaddset(&newmask,SIGINT);  /*添加信号SIGINT到信号集*/

if(sigprocmask(SIG_BLOCK,&newmask,&oldmask)<0)  /*信号集newmask设置为阻塞信号集*/

    perror(“error”);

sleep(5);

if(sigpending(&pendmask)<0)  /*把当前已递送到进程,却被阻塞的信号保存到进程的信号阻塞队列里*/

    perror(“error”);

if(sigismember(&pendmask,SIGINT))  /*检测进程阻塞队列里是否有SIGINT信号*/

    printf(“/nSIGINT pending/n”);

 

exit(0);

}

 

程序开始运行,如果我们在5秒钟内按”ctrl+c”,SIGINT信号会被传递到进程,但是由于进程设置了信号阻塞集,信号SIGINT在这个集合中,所有这个信号被阻塞。并由sigpend保存到进程的信号阻塞队列pendmask.然后我们用sigismember检测SIGINT是否在信号阻塞队列pendmask里。

 

文章转自:http://blog.chinaunix.net/u1/59291/showart.php?id=538597

你可能感兴趣的:(UNIX环境高级编程读书笔记(十)—信号 (4))