一、信号_Linux C(一)

一、信号_Linux C(一)

概念:信号是软件层面中断。信号的响应依赖中断。

同步:程序每一步执行什么内容是确定的。

异步:程序每一步执行什么内容是未知的。事件什么时候到来未知。

​ 异步事件的处理:查询法;通知法。

  1. 函数:signal();

  2. 信号的不可靠

  3. 可重入函数

  4. 信号的响应过程

  5. 常用函数

    • kill();
    • raise();
    • alarm();
    • pause();
    • abort();
    • system();
    • sleep();
  6. 信号集

  7. 信号屏蔽字 pending 集的处理

  8. 扩展

    • sigsuspend();
    • sigaction();
    • setitimer();
  9. 实时信号

1 signal

查看信号命令: kill -l

 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

其中编号 1~31 叫做标准信号,32~64 叫做实时信号。

  1. SIGINT为终端中断符,即在程序运行时在终端按下 ctrl + c 引发的中断。
  • signal 用来注册当前信号的行为。
void (*signal(int signum, void (*fun)(int)))(int);
SYNOPSIS
       #include <signal.h>

       typedef void (*sighandler_t)(int);

       sighandler_t signal(int signum, sighandler_t handler);

示例:

/**
 * signal 函数示例
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

void int_handler(int s){
    write(1, "!", 1);
}

int main(){

    //忽略 SIGINT 信号 ,SIG_IGN 为忽略信号
    //signal(SIGINT, SIG_IGN);

    //在程序未结束时,当收到SIGINT时,执行 int_handler 的动作
    //信号会打断阻塞的系统调用,当一直按住 ctrl + c 时程序会“快进”执行。
    signal(SIGINT, int_handler);

    for (int i = 0; i < 10 ; i++){
        write(1, "*" , 1);
        sleep(1);
    }


    return 0;
}

这里体现了信号会打断阻塞的系统调用,这样在许多阻塞的系统调用发生错误时可能存在假错,我们需要对错误类型判断。如下:

do{
    //尝试只读打开文件
    fd = fopen(FILENAME, O_RDONLY);
    
    if (fd < 0){ //如果打开失败
        
        if (errno ! = EINTR){ //不是被信号打断,则报错退出
            perroor("open()");
            exit(1);
        }
    }
}while (fd < 0);//直到成功打开文件跳出循环

2 信号的不可靠

信号的不可靠指的是信号的行为是不可靠的。(不是指信号会丢失,但是标准信号一定会发生丢失,而实时信号不会)。一个信号在处理这个行为的同时又有一个相同的信号到达,由于现场的布置是由内核完成的,就有可能布置在同一个位置,使得第二次的现场将第一次的现场覆盖掉。

3 可重入函数

为了解决信号的不可靠问题。可重入函数是指第一次调用还没结束时发生第二次调用不会发生错误。

所有的系统调用都是可重入的,一部分的库函数也是可重入的,例:memcpy可以用在带有信号的程序中,而许多库函数为了能够在含有信号的情况下使用也添加了function_r版本的方法,以满足需求。

4 信号的响应过程

当前内核为每一个进程维护了两个位图,一个叫信号屏蔽字(mask),一个叫pending(一般都为32位)。

mask:记录信号的状态,一般情况初始全为1。

pending:用来记录发生了那些信号,一般情况初始全为0。

**当一个进程从内核态回到用户态时(从中断中恢复到现场),会有机会进行一次计算,计算 mask & pending,**如果结果全为0,则说明没有收到信号,进程返回原地址继续执行。

如果指定位的信号为1,说明收到了该信号。将栈内的返回现场地址悄悄改成该信号的处理函数的入口,将mask和pending的该信号的指示位都修改为0并执行信号处理函数。处理函数执行完毕后,将栈内的返回现场地址改回原地址,并将mask的指示位修改为1。

信号从收到到响应有不可避免的延迟,这个延迟是由有信号的响应机制是严重依赖系统的中断才能处理信号造成的。由于信号是由pending保存,位图不能够计数也不能累加故会存在信号丢失。标准信号 的响应没有严格的顺序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值