您的位置:首页 > 运维架构 > Linux

linux进程通信----信号的处理

2013-07-04 18:15 330 查看
在了解了信号的产生和捕获之后,接下来就是对信号的具体操作了,特定的信号是与一定的进程相联系的,一个进程可以选择忽略一些信号和处理一些信号,进程可以选择如何处理信号,所以信号是与特定的进程相联系的,因此首先就要建立进程与信号之间的对应关系,这就是信号的处理

ps:信号的注册和信号处理之间的区别:前者信号是主动方,后者是进程是主动方,信号的注册是进程选择处理特定信号之后特定信号的主动行为。

信号处理有两种方法一种是简单的signal()函数,一种是使用信号集函数组

1.信号处理函数

使用signal()时只需指出要处理的信号和处理函数即可,他主要用于前32中非实时的信号,不支持信号传递信息,但使用简单方便,所以得到程序员的欢迎,linux提供一个更健壮,更新的信号处理的函数sigaction(),推荐使用这个函数。

signal()函数语法如下:



这个函数原型有点复杂,可以使用下面的typedef进行替换说明:

typedef void sign(int) ;
sign *signal(int, header*) ;
函数原型指向一个无返回值带一个int类型参数的函数指针,而该函数原型带有两个参数,第二个参数是自定义的处理函数的指针

sigaction()函数语法如下:





sigaction()函数第二个和第三个参数都有一个signaction结构,其原型如下:

struct sigaction
{
	void (*sa_handler)(int signo) ;
	sigset_t sa_mask ;
	int sa_flags ;
	void (*sa_restore)(void) ;
};
sa_handler---是一个函数指针,指定信号处理函数,除了用户自定义的处理函数外,还可以是SIG_DFL(采用缺省的处理方式)或SIG_IGN(忽略信号),处理函数只有一个参数,就是信号值

sa_mask-----信号集,可以指定在信号处理过程中哪些信号应当被屏蔽,在调用处理函数之前,信号集需要加入信号的信号屏蔽字中

sa_flags----包含了许多标志位,是对信号处理的各个选项,常用选项如下:



使用signal()的实例:

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
void my_func(int sign_no)
{
    if (sign_no == SIGINT)
    {
        printf("i have get SIGNINT\n") ;
    }
    else if (sign_no == SIGQUIT)
    {
        printf("i have get SIGQUIT\n") ;
    }
}

int main()
{
    printf("waiting for signal or sigquit...\n") ;
    //当信号来临是由my_func函数处理
    signal(SIGINT, my_func) ;
    signal(SIGQUIT, my_func) ;
    pause() ;
    exit(0) ;
}



使用sigaction()函数的如下:

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
void my_func(int sign_no)
{
    if (sign_no == SIGINT)
    {
        printf("i have get SIGNINT\n") ;
    }
    else if (sign_no == SIGQUIT)
    {
        printf("i have get SIGQUIT\n") ;
    }
}
int main()
{
    struct sigaction action ;
    printf("waitfor signal SIGINT OR SIGQUIT...\n ") ;
    //初始化action结构体
    action.sa_handler = my_func ;//指定处理函数
    sigemptyset(&action.sa_mask) ;//将信号集加入信号屏蔽字中
    action.sa_flags = 0 ;
		//定义相关处理函数
    sigaction(SIGINT, &action, 0) ;
    sigaction(SIGQUIT, &action , 0) ;
    pause() ;
    exit(0) ;
}
运行结果如下:



可见两种方法都能实现信号的处理

下面说一下信号集函数组:

信号集函数组处理信号时涉及一系列的函数,这些函数按照调用的先后顺序,可以分为几大功能块:创建信号集合,注册信号处理函数,检测信号

(1)创建信号集合

创建信号集合主要用于处理用户感兴趣的一些信号,函数包括一下几个:

sigemptyset():将信号集合初始化为空
sigfillset():将信号初始化为包含已定义的信号的集合
sigaddset():将指定信号加入到信号集合中去
sigdelset():将指定信号从信号集中删除
sigismember():查询制定信号是否在信号集合中

(2)注册信号处理函数----注册信号处理函数主要用于决定进程如何处理函数,注意的是信号集里的函数并不一定是可以处理的信号,只有信号处于非阻塞状态时才会真正起作用,所以需要使用sigprocmask()检测并更改信号屏蔽字(信号屏蔽字是用来指定当前被阻塞的一组信号,他们不会被进程接收),然后使用sigaction()指定接收到特定信号的处理函数,最后是检测阻塞的信号使用sigpending(),进程可以通过这个函数去检测那些被阻塞的函数,然后决定他们的行为

下面是创建信号集合的函数语法:





如此就指定了信号集合set

sigprocmask的函数语法:



ps:如果set是一个非空指针,那么参数how表示函数的操作方式;如果how为空,则表示忽略此操作

sigpending()函数的语法要点:



所以处理信号的流程如下:



下面是处理信号的实例:

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
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 ;
    if (sigemptyset(&set) < 0)//信号集初始化为空
    {
        perror("sigemptyset") ;
        exit(1) ;
    }
    if (sigaddset(&set, SIGINT) < 0)//将SIGINT加入到信号集set
    {
        perror("sigaddset") ;
        exit(1) ;
    }
    if (sigaddset(&set, SIGQUIT) < 0)//将SIGQUIT加入到信号集set中
    {
        perror("sigaddset") ;
        exit(1) ;
    }
    if (sigismember(&set, SIGINT))
    {
        sigemptyset(&action1.sa_mask) ;//没有屏蔽的信号
        action1.sa_handler = my_func ;
        action1.sa_flags = 0 ;
        sigaction(SIGINT, &action1, NULL) ;//定义SIGINT的处理函数my_func
    }
    if (sigismember(&set, SIGQUIT))
    {
        sigemptyset(&action2.sa_mask) ;//没有屏蔽的信号
        action2.sa_handler = SIG_DFL ;
        action2.sa_flags = 0 ;
        sigaction(SIGQUIT, &action2, NULL) ;//定义SIGQUIT的处理为默认
    }

    if (sigprocmask(SIG_BLOCK, &set, NULL) < 0)//阻塞信号集set中的信号
    {
        perror("sigprocmask") ;
        exit(1) ;
    }
    else
    {
        printf("signal set was blocked, press any key!\n") ;
        getchar() ;
    }
    if (sigprocmask(SIG_UNBLOCK, &set, NULL) < 0)//将set中的信号变为非阻塞态
    {
        perror("sigprocmask") ;
        exit(1) ;
    }
    else
    {
        printf("signal set is in unblock state\n") ;
    }
    while(1) ;//循环处理
    exit(0) ;
}
程序运行如下:



如果们在解锁之前发送SIGINT,SIGQUIT信号,信号不会丢失,等到非阻塞状态时,这些信号还是会被发送给程序的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: