(P20)信号安装函数:sigaction

1.sigaction函数

  • sigaction
    包含头文件<signal.h>;
    功能:sigaction函数用于改变进程接收特定信号后的行为
    act:信号的处理函数
    old:信号安装之前,关联的行为
原型:
 int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);


参数:
第一个参数:
该函数的第一个参数为信号的值,可以为除SIGKILL以及SIGSTOP外的任何一个特定有效的信号(因为为这俩信号定义自己的处理函数,将
导致信号安装错误)
第二个参数:
第二个参数是指向结构sigaction的一个实例的指针,在结构sigaction的实例中,指定了对特定信号的处理,可以为空,进程会以
缺省的方式对信号进行处理
第三个参数:
oldact指向的对象用来保存原来对相应信号的处理,可指定oldact为NULL

返回值:
函数成功返回0,失败返回-1

2.sigaction结构体

  • sigaction结构体
    第2个参数最为重要,其中包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程中应屏蔽掉哪些函数等等
    man sigaction
struct sigaction 
{
	//下面的2个声明(函数指针)只能任选其一
    void     (*sa_handler)(int);//对不可靠信号安装的原型,对可靠信号安装也可以使用该原型,只不过此时它不能传递数据
    void     (*sa_sigaction)(int, siginfo_t *, void *);//对可靠信号安装的原型
    sigset_t   sa_mask;//可以指定一个信号屏蔽字,用来屏蔽放到屏蔽字当中的信号
    int        sa_flags;//影响信号的行为
    void     (*sa_restorer)(void);//该字段可以不用关心
};

3.sigaction实例

  • eg1:P20sigaction.c
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.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;

    //NULL表示不关心信号之前的行为
    //sigaction关联一个动作
    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);
}
  • 测试:改变了信号的输出行为
    在这里插入图片描述
  • eg:P20sigaction1.c
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.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);
//用sigaction模拟signal函数,类型可以从man signal中看到,所以这么写
_sighandler my_signal(int sig, _sighandler_t handler);

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;

}

//信号原来的行为从oldact返回回来
//my_signal等价于signal函数
//signal函数既可以安装可靠信号,也可以安装不可靠信号
//但是在安装可靠信号时,函数指针只能是handler,不能用可以传递更多数据的函数
_sighandler my_signal(int sig, _sighandler_t handler)
{
    strucy sigaction act;
    struct  sigaction oldact;
    act.sa_handler = handler;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;

    //信号原来的行为从oldact返回回来
    if (sigaction(sig, &act, &oldact) <0)
        return SIG_ERR;

    return oldact.handler;//返回信号原来的处理函数
}


void handler(int sig)
{
    printf("recv a sig = %d\n", sig);
}
  • 测试:
    signal也是在可靠的机制上进行安装信号的,当信号安装完毕后,当信号处理函数被执行后,信号的默认行为是不会自动恢复的。我们可以认为他是调用sigaction来实现的。实际上,内核代码是调用do_sigaction来实现的

在这里插入图片描述

  • eg:P20sa_mask.c
    sa_mask如何改变信号的行为
    在这个信号处理函数执行的时候,能否屏蔽其他信号?
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.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);
    act.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);
}
  • 测试:
    在还没有返回的时候,出现了3号信号,程序退出,说明在2号信号处理函数执行的时候,没有屏蔽3号信号,直接被递达了
    在这里插入图片描述
    按下ctrl \并没有马上退出来,因为该信号在先前信号还没有运行完的时候阻塞了,直到先前信号运行完毕,该信号才能递达
    在这里插入图片描述
    在这里插入图片描述

  • eg:P20sa_,ask1.c
    注意区别:sa_mask中的掩码能阻塞信号,当处理函数在执行的过程中,加入到掩码中的信号将要被阻塞,直到handler返回才能被递达;
    sigpromask表示将这些集合中的信号添加到进程的信号屏蔽字当中,这些信号就不能被递达了,即使发生了

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.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;


    //将SIGINT加入到了进程中的信号屏蔽字,将对应的位置为1
    //SIGINT信号发生的时候,不能被递达,会处于pending未决状态
    sigset_t s;
    sigemptyset(&s);
    sigaddset(&s, SIGINT);
    sigprocmask(SIG_BLOCK, &s, NULL);

    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);
}
  • 测试:
    在这里插入图片描述
    按下ctrl \就可以退出程序,因为他没有阻塞,所以他被递达了

  • Makefile

.PHONY:clean all
CC=gcc
CFLAGS=-Wall -g
BIN=01sigac
all:$(BIN)
%.o:%.c
	$(CC) $(CFLAGS) -c $< -o $@
clean:
	rm -f *.o $(BIN)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喜欢打篮球的普通人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值