信号 捕捉

signal 函数

作用:注册一个信号捕捉函数(注册而非创建)

原型

  • sighandler_t signal(int signum, sighandler_t handler);
  • typedef void (*sighandler_t)(int);

案例一: signal函数 捕捉 ctrl+c 触发事件

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

void sys_err(const char *str)
{
    perror(str);
    exit(1);
}

void sig_catch(int signo)
{
    printf("catch you!!! %d\n", signo);
    return;
}


int main(int argc, char *argv[])
{
    signal(SIGINT, sig_catch);

    //  
    //
    //
    
    while(1);

    return 0;
}

 sigaction 函数

作用:修改信号处理动作(通常在Linux用其来注册一个信号的捕捉函数)

原型:int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); 

                成功:0;失败:-1,设置errno

        参数:

                act:传入参数,新的处理方式。

                oldact:传出参数,旧的处理方式

struct 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_restorer:该元素是过时的,不应该使用,POSIX.1标准将不指定该元素。(弃用)

         sa_sigaction:当sa_flags被指定为SA_SIGINFO标志时,使用该信号处理程序。(很少使用) 

重点掌握:

         ① sa_handler:指定信号捕捉后的处理函数名(即注册函数)。也可赋值为SIG_IGN表忽略 或 SIG_DFL表执行默认动作

         ② sa_mask: 调用信号处理函数时,所要屏蔽的信号集合(信号屏蔽字)。注意:仅在处理函数被调用期间屏蔽生效,是临时性设置。

         ③ sa_flags:通常设置为0,表使用默认属性。

案例二: sigaction 函数 捕捉 ctrl+c 触发事件 

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

void sys_err(const char *str)
{
    perror(str);
    exit(1);
}

void sig_catch(int signo)  //捕捉函数(回调函数)
{
    if(signo == SIGINT){
         printf(" SIGINT  catch you!!! %d\n", signo);
    } else if(signo == SIGQUIT){
         printf(" SIGQUIT  catch you!!! %d\n", signo);
    }
    return;
}


int main(int argc, char *argv[])
{
    struct sigaction act, oldact;

    act.sa_handler = sig_catch;  //设置回调函数
    sigemptyset(&(act.sa_mask)); //设置屏蔽字 清空sa_mask 在捕捉函数期间生效
    act.sa_flags = 0;            //设置默认属性

    int ret = sigaction(SIGINT, &act, &oldact); //注册信号捕捉函数 ctrl + c
    if(ret == -1){
        sys_err("sigaction error");
    }

    ret = sigaction(SIGQUIT, &act, &oldact); //注册信号捕捉函数 ctrl + \
    
    while(1);

    return 0;
}

信号捕捉特性

  1. 进程正常运行时,默认PCB中有一个信号屏蔽字,假定为☆,它决定了进程自动屏蔽哪些信号。当注册了某个信号捕捉函数,捕捉到该信号以后,要调用该函数。而该函数有可能执行很长时间,在这期间所屏蔽的信号不由☆来指定。而是用sa_mask来指定。调用完信号处理函数,再恢复为☆。
  2. XXX信号捕捉函数执行期间,XXX信号自动被屏蔽。
  3. 阻塞的常规信号不支持排队,产生多次只记录一次。(后32个实时信号支持排队)

案例三: 验证信号捕捉特性

 从结果很容易看出在信号处理函数执行期间,该信号多次递送,那么只在处理函数之行结束后,处理一次。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
void do_sig(int a)
{
    printf("hello world!\n");
    sleep(10);//休息10秒 让函数执行久一点
}
int main(void)
{      
    if (signal(SIGINT, do_sig)== SIG_ERR)
    {
        perror("signal");
        exit(1);
    }
    while (1) {
        printf("---------------------\n");
        sleep(1);
    }
    return 0;
}

 内核实现信号捕捉过程

猜你喜欢

转载自blog.csdn.net/weixin_43200943/article/details/129843932