【Linux】signal 和 sigaction 两个信号捕捉函数

sigaction的用法要复杂一些,但一般都是用sigaction,signal依据不同的标准可能有不同的用法变化,sigaction比较稳定,只有一种固定的标准

signal 信号捕捉函数

在上一篇文章中(【Linux】alarm 函数和 setitimer 函数),我使用了 setitimer 函数来实现定时的功能,首次是在3秒后打印,然后每隔2秒打印一次。

但是当执行了示例代码的时候,发现只是在3秒后进行了打印,却没有每隔两秒打印一次。这是因为我在示例代码中setitimer 函数的第一个参数为ITIMER_REAL(真实时间),当时间到达就会向进程发送 SIGALRM ,而进程在接收到该信号后就停止了。所以没有看到周期性的执行打印

所以我需要对进程收到的信号进行捕捉,防止进程在接收到该信号后就自动终止了

1、函数解析

/*
    #include <signal.h>
    typedef void (*sighandler_t)(int);
    sighandler_t signal(int signum, sighandler_t handler);
        - 功能:设置某个信号的捕捉行为
        - 参数:
            - signum: 要捕捉的信号
            - handler: 捕捉到信号要如何处理
                - SIG_IGN : 忽略信号
                - SIG_DFL : 使用信号默认的行为
                - 回调函数 :  这个函数是内核调用,程序员只负责写,捕捉到信号后如何去处理信号。
                回调函数:
                    - 需要程序员实现,提前准备好的,函数的类型根据实际需求,看函数指针的定义
                    - 不是程序员调用,而是当信号产生,由内核调用
                    - 函数指针是实现回调的手段,函数实现之后,将函数名放到函数指针的位置就可以了。

        - 返回值:
            成功,返回上一次注册的信号处理函数的地址。第一次调用返回NULL
            失败,返回SIG_ERR,设置错误号
            
    SIGKILL SIGSTOP不能被捕捉,不能被忽略。
*/

2、代码示例

#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void myalarm(int num) {
    
    
    printf("捕捉到了信号的编号是:%d\n", num);
    printf("xxxxxxx\n");
}

// 过3秒以后,每隔2秒钟定时一次
int main() {
    
    

    // 注册信号捕捉
    // signal(SIGALRM, SIG_IGN);
    // signal(SIGALRM, SIG_DFL);
    // void (*sighandler_t)(int); 函数指针,int类型的参数表示捕捉到的信号的值。
    signal(SIGALRM, myalarm);//myalarm是我们自己定义的回调函数

    struct itimerval new_value;

    // 设置间隔的时间
    new_value.it_interval.tv_sec = 2;
    new_value.it_interval.tv_usec = 0;

    // 设置延迟的时间,3秒之后开始第一次定时
    new_value.it_value.tv_sec = 3;
    new_value.it_value.tv_usec = 0;

    int ret = setitimer(ITIMER_REAL, &new_value, NULL); // 非阻塞的
    printf("定时器开始了...\n");

    if(ret == -1) {
    
    
        perror("setitimer");
        exit(0);
    }

    getchar();

    return 0;
}

具体过程:立刻打印出"定时器开始了…",隔三秒后打印处第一次,随后每隔两秒打印一次
在这里插入图片描述

sigaction 信号捕捉函数

1、函数解析

/*

	#include <signal.h>
	int sigaction(int signum, const struct sigaction *act,
							struct sigaction *oldact);
		- 功能:检查或者改变信号的处理。信号捕捉
		- 参数:             
			- signum : 需要捕捉的信号的编号或者宏值(信号的名称)             
			- act :捕捉到信号之后的处理动作             
			- oldact : 上一次对信号捕捉相关的设置,一般不使用,传递NULL
		- 返回值:             
			成功 0             
			失败 -1
			
	struct sigaction {
    
    
	// 函数指针,指向的函数就是信号捕捉到之后的处理函数         
	void     (*sa_handler)(int);
	
	// 不常用         
	void     (*sa_sigaction)(int, siginfo_t *, void *);
	
	// 临时阻塞信号集,在信号捕捉函数执行过程中,临时阻塞某些信号。         
	sigset_t   sa_mask;
	
	// 使用哪一个信号处理对捕捉到的信号进行处理         
	// 这个值可以是0,表示使用sa_handler,也可以是SA_SIGINFO表示使用sa_sigaction         
	int        sa_flags;    
	     
	// 被废弃掉了         
	void     (*sa_restorer)(void);
	};
	
*/

2、代码示例

#include <sys/time.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <signal.h>
void myalarm(int num) {
    
         
	printf("捕捉到了信号的编号是:%d\n", num);     
	printf("xxxxxxx\n"); 
}

// 过3秒以后,每隔2秒钟定时一次 
int main() {
    
    
	struct sigaction act;
	act.sa_flags = 0;     
	act.sa_handler = myalarm;     
	sigemptyset(&act.sa_mask);  // 清空临时阻塞信号集

	// 注册信号捕捉     
	sigaction(SIGALRM, &act, NULL);

	struct itimerval new_value;      

	// 设置间隔的时间     
	new_value.it_interval.tv_sec = 2;     
	new_value.it_interval.tv_usec = 0;

	// 设置延迟的时间,3秒之后开始第一次定时     
	new_value.it_value.tv_sec = 3;     
	new_value.it_value.tv_usec = 0;

	int ret = setitimer(ITIMER_REAL, &new_value, NULL); // 非阻塞的     
	printf("定时器开始了...\n");

	if(ret == -1) {
    
             
	perror("setitimer");         
	exit(0);     
	}

	// getchar();     
	while(1);      
	return 0; 
}

在这里插入图片描述

内核实现信号捕捉的过程

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/mhyasadj/article/details/130790481