signal函数、sigaction函数及信号集(sigemptyset,sigaddset)操作函数

信号是与一定的进程相联系的。也就是说,一个进程可以决定在进程中对哪些信号进行什 么样的处理。例如,一个进程可以忽略某些信号而只处理其他一些信号;另外,一个进程还可以选择如何处理信号。总之,这些总与特定的进程相联系的。因此,首 先要建立其信号和进程的对应关系,这就是信号的安装登记。

Linux 主要有两个函数实现信号的安装登记:signal和sigaction。其中signal在系统调用的基础上实现,是库函数。它只有两个参数,不支持信号 传递信息,主要是用于前32个非实时信号的安装;而sigaction是较新的函数(由两个系统调用实现:sys_signal以及 sys_rt_sigaction),有三个参数,支持信号传递信息,主要用来与sigqueue系统调用配合使用。当然,sigaction同样支持非 实时信号的安装,sigaction优于signal主要体现在支持信号带有参数。

对 于应用程序自行处理的信号来说,信号的生命周期要经过信号的安装登记、信号集操作、信号的发送和信号的处理四个阶段。信号的安装登记指的是在应用程序中, 安装对此信号的处理方法。信号集操作的作用是用于对指定的一个或多个信号进行信号屏蔽,此阶段对有些应用程序来说并不需要。信号的发送指的是发送信号,可 以通过硬件(如在终端上按下Ctrl-C)发送的信号和软件(如通过kill函数)发送的信号。信号的处理指的是操作系统对接收信号进程的处理,处理方法 是先检查信号集操作函数是否对此信号进行屏蔽,如果没有屏蔽,操作系统将按信号安装函数中登记注册的处理函数完成对此进程的处理。

1.   signal函数

(1)函数说明

在signal函数中,有两个形参,分别代表需要处理的信号编号值和处理信号函数的指针。它主要是用于前32种非实时信号的处理,不支持信号的传递信息。但是由于使用简单,易于理解,因此在许多场合被程序员使用。

对 于Unix系统来说,使用signal函数时,自定义处理信号函数执行一次后失效,对该信号的处理回到默认处理方式。下面以一个例子进行说明,例如一程序 中使用signal(SIGQUIT, my_func)函数调用,其中my_func是自定义函数。应用进程收到SIGQUIT信号时,会跳转到自定义处理信号函数my_func处执行,执行 后信号注册函数my_func失效,对SIGQUIT信号的处理回到操作系统的默认处理方式,当应用进程再次收到SIGQUIT信号时,会按操作系统默认 的处理方式进行处理(即不再执行my_func处理函数)。而在Linux系统中,signal函数已被改写,由sigaction函数封装实现,则不存 在上述问题。

(2)signal函数原型


signal(设置信号处理方式)


所需头文件


#include


函数说明


设置信号处理方式。signal()会依参数signum指定的信号编号来设置该信号的处理函数。当指定的信号到达时就会跳转到参数handler指定的函数执行


函数原型


void (*signal(int signum,void(* handler)(int)))(int)


函数传入值


signum


指定信号编号


handle


SIG_IGN:忽略参数signum指定的信号


SIG_DFL:将参数signum指定的信号重设为核心预设的信号处理方式,即采用系统默认方式处理信号


自定义信号函数处理指针


函数返回值


成功


返回先前的信号处理函数指针


出错


SIG_ERR(-1)


附加说明


在Unix环境中,在信号发生跳转到自定的handler处理函数执行后,系统会自动将此处理函数换回原来系统预设的处理方式,如果要改变此情形请改用sigaction函数。在Linux环境中不存在此问题

signal函数原型比较复杂,如果使用下面的typedef,则可使其简化。

typedef void sign(int);

sign *signal(int, handler *);

可见,该函数原型首先整体指向一个无返回值带一个整型参数的函数指针,也就是信号的原始配置函数。接着该原型又带有两个参数,其中的第二个参数可以是用户自定义的信号处理函数的函数指针。对这个函数格式可以不理解,但需要学会模仿使用。

(3) signal函数使用实例

该示例表明了如何使用signal函数进行安装登记信号处理函数。当该信号发生时,登记的信号处理函数会捕捉到相应的信号,并做出给定的处理。这里,my_func就是信号处理的函数指针。读者还可以将my_func改为SIG_IGN或SIG_DFL查看运行结果。

signal.c源代码如下:

#include

#include

#include

/*自定义信号处理函数*/

void my_func(int sign_no)

{

if(sign_no==SIGINT)

printf("I have get SIGINT\n");

else if(sign_no==SIGQUIT)

printf("I have get SIGQUIT\n");

}

int main()

{

printf("Waiting for signal SIGINT or SIGQUIT \n ");

/*发出相应的信号,并跳转到信号处理函数处*/

signal(SIGINT, my_func);

signal(SIGQUIT, my_func);

pause();

pause();

exit(0);

}

编译 gcc signal.c –o signal。

执行 ./signal,执行结果如下:

Waiting for signal SIGINT or SIGQUIT

I have get SIGINT       /*按下Ctrl+C,操作系统就会向进程发送SIGINT信号*/

I have get SIGQUIT      /*按下Ctrl-\(退出),操作系统就会向进程发送SIGQUIT信号*/

2.   sigaction函数

(1)sigaction函数原型

sigaction函数用来查询和设置信号处理方式,它是用来替换早期的signal函数。sigaction函数原型及说明如下:


sigaction(查询和设置信号处理方式)


所需头文件


#include


函数说明


sigaction()会依参数signum指定的信号编号来设置该信号的处理函数


函数原型


int sigaction(int signum,const struct sigaction *act ,struct sigaction *oldact)


函数传入值


signum


可以指定SIGKILL和SIGSTOP以外的所有信号


act


参数结构sigaction定义如下

struct sigaction

{

void (*sa_handler) (int);

void  (*sa_sigaction)(int, siginfo_t *, void *);

sigset_t sa_mask;

int sa_flags;

void (*sa_restorer) (void);

}

①    sa_handler:此参数和signal()的参数handler相同,此参数主要用来对信号旧的安装函数signal()处理形式的支持

②    sa_sigaction:新的信号安装机制,处理函数被调用的时候,不但可以得到信号编号,而且可以获悉被调用的原因以及产生问题的上下文的相关信息。

③    sa_mask:用来设置在处理该信号时暂时将sa_mask指定的信号搁置

④    sa_restorer: 此参数没有使用

⑤    sa_flags:用来设置信号处理的其他相关操作,下列的数值可用。可用OR 运算(|)组合

?   A_NOCLDSTOP:如果参数signum为SIGCHLD,则当子进程暂停时并不会通知父进程

?   SA_ONESHOT/SA_RESETHAND:当调用新的信号处理函数前,将此信号处理方式改为系统预设的方式

?   SA_RESTART:被信号中断的系统调用会自行重启

?   SA_NOMASK/SA_NODEFER:在处理此信号未结束前不理会此信号的再次到来

?   SA_SIGINFO:信号处理函数是带有三个参数的sa_sigaction


oldact


如果参数oldact不是NULL指针,则原来的信号处理方式会由此结构sigaction返回


函数返回值


成功:0


出错:-1,错误原因存于error中


附加说明


信号处理安装的新旧两种机制:

①     使用旧的处理机制:struct sigaction act;  act.sa_handler=handler_old;

②     使用新的处理机制:struct sigaction act; act.sa_sigaction=handler_new;

并设置sa_flags的SA_SIGINFO位


错误代码


EINVAL:参数signum不合法,或是企图拦截SIGKILL/SIGSTOP信号

EFAULT:参数act,oldact指针地址无法存取

EINTR:此调用被中断

(2)sigaction函数使用实例

sigaction.c源代码如下:

#include

#include

#include

#include

#include

void new_op(int, siginfo_t *, void *);

int main(int argc,char**argv)

{

struct sigaction act;

int sig;

sig=atoi(argv[1]);

sigemptyset(&act.sa_mask);

act.sa_flags=SA_SIGINFO;

act.sa_sigaction=new_op;

if(sigaction(sig,&act,NULL) < 0)

{

perror("install sigal error");

return -1 ;

}

while(1)

{

sleep(2);

printf("wait for the signal\n");

}

return 0 ;

}

void new_op(int signum,siginfo_t *info,void *myact)

{

printf("receive signal %d\n", signum);

sleep(5);

}

编译 gcc sigaction.c -o sigaction。

执行 ./sigaction 2,执行结果如下:

wait for the signal

receive signal 2       /*按下Ctrl+C */

退出                   /*按下Ctrl-\ */

3.   信号集操作函数

由 于有时需要把多个信号当作一个集合进行处理,这样信号集就产生了,信号集用来描述一类信号的集合,Linux所支持的信号可以全部或部分的出现在信号集 中。信号集操作函数最常用的地方就是用于信号屏蔽。比如有时候希望某个进程正确执行,而不想进程受到一些信号的影响,此时就需要用到信号集操作函数完成对 这些信号的屏蔽。

信号集操作函数按照功能和使用顺序分为三类,分别为创建信号集函数,设置信号屏蔽位函数和查询被搁置(未决)的信号函数。创建信号集函数只是创建一个信号 的集合,设置信号屏蔽位函数对指定信号集中的信号进行屏蔽,查询被搁置的信号函数是用来查询当前“未决”的信号集。信号集函数组并不能完成信号的安装登记 工作,信号的安装登记需要通过sigaction函数或signal函数来完成。

查 询被搁置的信号是信号处理的后续步骤,但不是必需的。由于有时进程在某时间段内要求阻塞一些信号,程序完成特定工作后解除对该信号阻塞,这个时间段内被阻 塞的信号称为“未决”信号。这些信号已经产生,但没有被处理,sigpending函数用来检测进程的这些“未决”信号,并进一步决定对它们做何种处理 (包括不处理)。

(1)    创建信号集函数

创建信号集函数有如下5个:

①    sigemptyset:初始化信号集合为空。

②    sigfillset:把所有信号加入到集合中,信号集中将包含Linux支持的64种信号。

③    sigaddset:将指定信号加入到信号集合中去。

④    sigdelset:将指定信号从信号集中删去。

⑤    sigismember:查询指定信号是否在信号集合之中。


创建信号集合函数原型


所需头文件


#include


函数原型


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(sigset_t *set,int signum)


函数传入值


set:信号集


signum:指定信号值


函数返回值


成功:0(sigismember函数例外,成功返回1,失败返回 0)


出错:-1,错误原因存于error中

(2)    设置信号屏蔽位函数

每个进程都有一个用来描述哪些信号递送到进程时将被阻塞的信号集,该信号集中的所有信号在递送到进程后都将被阻塞。调用函数sigprocmask可设定信号集内的信号阻塞或不阻塞。其函数原型及说明如下:


sigprocmask(设置信号屏蔽位)


所需头文件


#include


函数原型


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


函数传入值


how(决定函数的操作方式)


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


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


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


set:指定信号集


oset:信号屏蔽字


函数返回值


成功:0


出错:-1,错误原因存于error中

(3)    查询被搁置(未决)信号函数

sigpending函数用来查询“未决”信号。其函数原型及说明如下:


sigpending(查询未决信号)


所需头文件


#include


函数说明


将被搁置的信号集合由参数set指针返回


函数原型


int sigpending(sigset_t *set)


函数传入值


set:要检测信号集


函数返回值


成功:0


出错:-1,错误原因存于error中


错误代码


EFAULT:参数set指针地址无法存取

EINTR:此调用被中断

(4)    对信号集操作函数的使用方法

对信号集操作函数的使用方法和顺序如下:

①      使用signal或sigaction函数安装和登记信号的处理。

②      使用sigemptyset等定义信号集函数完成对信号集的定义。

③      使用sigprocmask函数设置信号屏蔽位。

④      使用sigpending函数检测未决信号,非必需步骤。

(5)    信号集操作函数使用实例

该 实例首先使用sigaction函数对SIGINT信号进行安装登记,安装登记使用了新旧两种机制,其中#if 0进行注释掉的部分为信号安装的新机制。接着程序把SIGQUIT、SIGINT两个信号加入信号集,并把该信号集设为阻塞状态。程序开始睡眠30秒,此 时用户按下Ctrl+C,程序将测试到此未决信号(SIGINT);随后程序再睡眠30秒后对SIGINT信号解除阻塞,此时将处理SIGINT登记的信 号函数my_func。最后可以用SIGQUIT(Ctrl+\)信号结束进程执行。

sigset.c源代码如下:

#include

#include

#include

#include

#include

/*自定义的信号处理函数*/

#if 0

void my_funcnew(int signum, siginfo_t *info,void *myact)

#endif

void my_func(int signum)

{

printf("If you want to quit,please try SIGQUIT\n");

}

int main()

{

sigset_t set, pendset;

struct sigaction action1,action2;

/*设置信号处理方式*/

sigemptyset(&action1.sa_mask);

#if 0 /*信号新的安装机制*/

action1.sa_flags= SA_SIGINFO;

action1.sa_sigaction=my_funcnew;

#endif

/*信号旧的安装机制*/

action1.sa_flags= 0;

action1.sa_handler=my_func;

sigaction(SIGINT,&action1,NULL);

/*初始化信号集为空*/

if(sigemptyset(&set)<0)

{

perror("sigemptyset");

return -1 ;

}

/*将相应的信号加入信号集*/

if(sigaddset(&set,SIGQUIT)<0)

{

perror("sigaddset");

return -1 ;

}

if(sigaddset(&set,SIGINT)<0)

{

perror("sigaddset");

return -1 ;

}

/*设置信号集屏蔽字*/

if(sigprocmask(SIG_BLOCK,&set,NULL)<0)

{

perror("sigprocmask");

return -1 ;

}

else

{

printf("blocked\n");

}

/*测试信号是否加入该信号集*/

if(sigismember(&set,SIGINT)){

printf("SIGINT in set\n") ;

}

sleep( 30 ) ;

/*测试未决信号*/

if ( sigpending(&pendset) <0 )

{

perror("get pending mask error");

}

if(sigismember(&pendset, SIGINT) )

{

printf("signal SIGINT is pending\n");

}

sleep(30) ;

if(sigprocmask(SIG_UNBLOCK,&set,NULL)<0)

{

perror("sigprocmask");

return -1 ;

}

else

printf("unblock\n");

while(1)

{

sleep(1) ;

}

return 0 ;

}

编译 gcc sigset.c -o sigset。

执行 ./sigset,执行结果如下:

blocked

SIGINT in set   /*按下Ctrl+C */

signal SIGINT is pending

If you want to quit,please try SIGQUIT  /*按下Ctrl+C */

退出

摘录自《深入浅出Linux工具与编程》

时间: 2024-10-12 21:45:01

signal函数、sigaction函数及信号集(sigemptyset,sigaddset)操作函数的相关文章

2信号处理之:信号产生原因,进程处理信号行为,信号集处理函数,PCB的信号集,sigprocmask()和sigpending(),信号捕捉设定,sigaction,C标准库信号处理函数,可重入函数,

 1信号产生原因 2.进程处理信号行为 manpage里信号3中处理方式: SIG_IGN SIG_DFL                                            默认Term动作 a signal handling function 进程处理信号 A默认处理动作 term   中断 core    core(调试的时候产生) gcc –g file.c ulimit –c 1024 gdb a.out core ign      忽略 stop     停止

Linux进程间通信 -- 信号集函数 sigemptyset()、sigprocmask()、sigpending()、sigsuspend()

我们已经知道,我们可以通过信号来终止进程,也可以通过信号来在进程间进行通信,程序也可以通过指定信号的关联处理函数来改变信号的默认处理方式,也可以屏蔽某些信号,使其不能传递给进程.那么我们应该如何设定我们需要处理的信号,我们不需要处理哪些信号等问题呢?信号集函数就是帮助我们解决这些问题的. 有关Linux进程间使用信号通信的更多内容,可以参阅我的另一篇文章,Linux进程间通信 -- 信号量函数 signal().sigaction() 下面是信号函数集: 1.int sigemptyset(si

APUE学习笔记——10信号——信号接口函数 signal 和 sigaction

signal函数 signal函数是早起Unix系统的信号接口,早期系统中提供不可靠的信号机制.在后来的分支中,部分系统使用原来的不可靠机制定有signal函数,如 Solaris 10 .而更多的系统采用新语义 可靠信号机制,如4.4BSD. 出于signal函数不同系统的不统一性,我们一般使用sigaction函数取代它.关于sigaction函数,我们在本文后面做详细介绍. 函数原型: #include <signal.h> void (*signal(int signo,void (*

Linux进程间通信 -- 信号量函数 signal()、sigaction()

一.什么是信号 用过Windows的我们都知道,当我们无法正常结束一个程序时,可以用任务管理器强制结束这个进程,但这其实是怎么实现的呢?同样的功能在Linux上是通过生成信号和捕获信号来实现的,运行中的进程捕获到这个信号然后作出一定的操作并最终被终止. 信号是UNIX和Linux系统响应某些条件而产生的一个事件,接收到该信号的进程会相应地采取一些行动.通常信号是由一个错误产生的.但它们还可以作为进程间通信或修改行为的一种方式,明确地由一个进程发送给另一个进程.一个信号的产生叫生成,接收到一个信号

Linux 信号:signal 与 sigaction

0.Linux下查看支持的信号列表: [email protected]:~$ kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18) SIGCON

信号集 / 信号掩码(阻塞信号传递)

[摘自<Linux/Unix系统编程手册>] 信号集 sigemptyset() 函数初始化一个未包含任何成员的信号集.sigfillset() 函数则初始化一个信号集,使其包含所有信号(包括所有实时信号). #include <signal.h> int sigemptyset(sigset_t* set); int sigfillset(sigset_t* set); Both return 0 on success, or -1 on error 必须使用 sigemptys

10.12 信号集

我们需要使用一种数据类型来存储多个信号,这种类型称为信号集,我们将在函数sigprocmask等函数中使用这些数据结构(下一节中),用于告知内核不要允许集合中的信号出现,正如我们早些时候提到的,不同信号的数量可能会超过一个整形变量的Bit数量,所以通常来说,我们不能使用整形变量中的每一个Bit来存储每一个信号.POSIX.1定义了数据结构sigset_t用存储信号集,并且允许如下五个函数对其进行操作: #include<signal.h> int sigemptyset(sigset_t*se

10.11 信号集

我们需要使用一种数据类型来存储多个信号,这种类型称为信号集,我们将在函数sigprocmask等函数中使用这些数据结构(下一节中),用于告知内核不要允许集合中的信号出现,正如我们早些时候提到的,不同信号的数量可能会超过一个整形变量的Bit数量,所以通常来说,我们不能使用整形变量中的每一个Bit来存储每一个信号.POSIX.1定义了数据结构sigset_t用存储信号集,并且允许如下五个函数对其进行操作: #include <signal.h> int sigemptyset(sigset_t *

APUE学习笔记——10.11~10.13 信号集、信号屏蔽字、未决信号

如有转载,请注明出处:Windeal专栏 首先简述下几个概念的关系: 我们通过信号集建立信号屏蔽字,使得信号发生阻塞,被阻塞的信号即未决信号. 信号集: 信号集:其实就是一系列的信号.用sigset_t set表示. 数据类型:sigset_t 类似于整型(位数可能超过整型,因而不能用整型表示). 我们一般在sigprocmask()等函数中使用信号集,用于创建一系列进程要阻塞的信号,告诉内核不允许这些信号发生. 几个关于信号集的函数: #include <signal.h> int sige