linux系统编程之信号(五)

今天继续对信号进行学习,开始正入正题:

sigaction函数:
安装信号之前我们已经学过一个函数:signal,它最早是在unix上出现的,它是对不可靠信号进行安装的,之后出现了可靠信号和实时信号,所以新的安装函数sigaction函数就出现了,它的原形如下:
 
sigaction结构体:
通过man手册来查看一下它的说明:
 
 
 
关于这些说明,下面会用实验一一来阐述的,所以可以先了解一下既可。
sigaction示例:
下面先来看一下它的简单用法,也就是实现signal相同的功能来安装一个SIGINT信号:
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>


#define ERR_EXIT(m) \
    do \
    { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

void handler(int sig);

int main(int argc, char *argv[])
{
    struct sigaction act;//安装信号时需要传参
    act.sa_handler = handler;
    sigemptyset(&act.sa_mask);//先将sa_mask清空,关于这个属性的用法之后实验再说明
    act.sa_flags = 0;//同样将sa_flags设为0,这个实现不需要关心,之后会说明

    if (sigaction(SIGINT, &act, NULL) < 0)//安装信号
        ERR_EXIT("sigaction error\n");

    for (;;)
        pause();
    return 0;
}

void handler(int sig)
{
    printf("recv a sig=%d\n", sig);
}

编译运行:

实际上,对于signal这个安装函数是在可靠的机制之上进行的,也就是说可以认为它是通过sigaction来实现的,所以接下来,用sigaction来模拟signal函数的行为
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>


#define ERR_EXIT(m) \
    do \
    { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

void handler(int sig);
__sighandler_t my_signal(int sig, __sighandler_t handler);//这跟signal的信号安装函数声明一样,实现自己的signal
int main(int argc, char *argv[]) { /* struct sigaction act; act.sa_handler = handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (sigaction(SIGINT, &act, NULL) < 0) ERR_EXIT("sigaction error\n"); */ my_signal(SIGINT, handler); for (;;) pause(); return 0; } __sighandler_t my_signal(int sig, __sighandler_t handler) { struct sigaction act; struct sigaction oldact;//保存最初的行为 act.sa_handler = handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (sigaction(sig, &act, &oldact) < 0) return SIG_ERR; return oldact.sa_handler; } void handler(int sig) { printf("recv a sig=%d\n", sig); }

效果也是一样的,从以上代码可以看出,sigaction功能比signal要强大说了,其中有两个参数需要说明一下:

其中sa_handler只适合不可信号的安装,也就是说不可信号的安装不能用sa_sigaction,这个需要注意。

下面来说明一下sa_mask这个属性是什么效果,然后再回头来看下文字说明:

#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>


#define ERR_EXIT(m) \
    do \
    { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

void handler(int sig);

int main(int argc, char *argv[])
{
    struct sigaction act;
    act.sa_handler = handler;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;

    if (sigaction(SIGINT, &act, NULL) < 0)
        ERR_EXIT("sigaction error");

    for (;;)
        pause();
    return 0;
}

void handler(int sig)
{
    printf("recv a sig=%d\n", sig);
    sleep(5);//故意睡眠5秒是为了看在执行期间按了ctrl+\就能立马响应退出信号
}

编译运行:

可以看到,在执行信号处理函数期间,按ctrl+c时,并没有等待sleep5秒完之后,再执行退出动作,而是立马执行了,那能不能改变这种默认,也就是必须得等sleep5秒后再执行退出动作,答案是当然可以的,sa_mask属性就派上用场了:

结果如下:

从实验结果来看,在执行信号处理时,多次按了ctrl+c退出信号,并未立马执行退出动作,而是等执行完了才退出的,这也就是sa_mask的作用,实际上也就是上节学习的信号屏蔽字,不太清楚的可以参考博文:http://www.cnblogs.com/webor2006/p/3751210.html

思考一个问题:sa_mask的作用跟之前学的进程中的信号屏蔽字可以对其信号进行阻塞有什么区别呢?

#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>


#define ERR_EXIT(m) \
    do \
    { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

void handler(int sig);

int main(int argc, char *argv[])
{
    struct sigaction act;
    act.sa_handler = handler;
    sigemptyset(&act.sa_mask);
    //sigaddset(&act.sa_mask, SIGQUIT);//将其sa_mask注册去掉,也就是清零了
    act.sa_flags = 0;

    sigset_t s;
    sigemptyset(&s);
    sigaddset(&s, SIGINT);
    sigprocmask(SIG_BLOCK, &s, NULL);//这就是之前学的,将SIGINT加入到进程的屏蔽字中

    if (sigaction(SIGINT, &act, NULL) < 0)
        ERR_EXIT("sigaction error");

    for (;;)
        pause();
    return 0;
}

void handler(int sig)
{
    printf("recv a sig=%d\n", sig);
    sleep(5);
}

编译运行:

这时可以看到,信号被阻塞而压缩就不会执行处理函数了,这也是之前学过时的现象,从实验可以总结出:

sa_mask中指定的掩码也可以阻塞信号,它阻塞的信号是指函数在执行的过程当中,如果发生了在掩码级中指定的信号,信号将被阻塞,直到handler返回,这些信号才能被递达;

sigprocmask它所阻塞的信号表示将这些集合中的信号添加到进程信号屏蔽字当中,这些信号就不能被递达了,既使它发生了。

好了,今天的内容学到这,虽说内容不多,但是还是比较生涩的,下回继续!

 

posted on 2014-05-26 22:00  cexo  阅读(367)  评论(1编辑  收藏  举报

导航