zoukankan      html  css  js  c++  java
  • 信号(signal)

    1.信号本质

    1)信号是一种软件中断,是在软件层次上对中断的模拟;

    2)、在日常生活中也有很多信号,比如常见的红绿灯信号,我们看见红灯就停下,linux中的信号也是类似的,它提供一种机制告诉某个进程在某个时刻该怎样做

    2.信号产生(来源)

    1)硬件来源:比如我们按下了键盘或者其它硬件故障;

    2)软件来源:一些系统函数,最常见的发送信号的函数有kill, raise, alarm和pause;

    3.信号递送

      当导致产生信号的事件发生时,内核就产生一个信号。信号产生后,内核通常会在进程表中对进程设置某种形式的标志,当内核设置了这个标志,我们就说内核向一个进程递送了一个信号

    4.信号未决

      信号产生和递送之间的时间间隔称为信号未决

    5.进程对信号的处理方式(也称对信号的动作)

    1)忽略此信号:用signal函数指定SIG_IGN;SIGKILL和SIGSTOP不能被忽略

    2)捕捉此信号:用signal函数指定一个捕捉函数,指定信号被捕捉到就会调用这个捕捉函数;SIGKILL和SIGSTOP不能被捕捉

    3)执行系统默认动作:用signal函数指定SIG_DFL

    6.signal函数

    作用:设置进程对信号的处理方式(动作)

    void handler(int signo)
    {
        //捕捉函数
    }
    
    signal(SIGINT,SIG_IGN);
    signal(SIGINT,SIG_DFL);
    signal(SIGINT,process);

    7.sigaction函数

    作用:查看设置进程对信号的处理方式(动作),比signal()函数多了查看,sigaction函数能传递信息给捕捉函数,signal函数则不能。目前linux中的signal()是通过sigaction()函数实现的。

    8.信号排队

      每个进程有一个信号屏蔽字,规定了当前要阻塞递送到该进程的信号集(unix提供sigprocmask函数可以获得和更改屏蔽字),对于被阻塞的信号,如果进程对该信号的动作是捕捉或系统默认(即不是忽略),则内核将为该信号保持为未决状态,直到该信号解除阻塞或将对该信号的动作更改为忽略。在这之前,如果这种信号发生了多次,则发生未决信号排队

    9.不可靠信号

    早期unix系统的信号为不可靠信号,它们有下面两点特性(问题):

    1)进程对某种信号的处理方式进行设置后(早期的signal函数),第一次接收到这种信号,进程按所设置的方式处理,在这之后,这种信号的处理方式就会被自动重置为系统默认值

    所以当信号的处理方式设成捕捉时,一般会在捕捉函数的开头进行信号处理方式的重建

     1 int sig_int();//捕捉函数
     2 .
     3 .
     4 .
     5 signal(SIGINT, sig_int);//设置信号处理方式
     6 .
     7 .
     8 .
     9 sig_int()
    10 {
    11     signal(SIGINT, sig_int);//信号处理方式的重建
    12     .
    13     .
    14 }

    但是这种方法也有问题:捕捉到SIGINT,第5行执行,转到第9行调用sig_int(),再进入函数执行第11行,在执行完第5行后到执行第11行前的这段时间里,对SIGINT的处理方式是系统默认值,如果这时发生了SIGINT中断,则程序就终止了。

    2)信号可能丢失:对于阻塞信号,不发生未决信号排队,信号阻塞解除后,仅传送该种信号一次,后来的该种信号都将丢失

    9.1Linux下的不可靠信号

    1)Linux对不可靠信号机制做了改进:信号的处理方式不会被自动重置为系统默认值。因此,Linux下的不可靠信号问题主要指的是信号可能丢失。

    2)Linux中信号编号小于SIGRTMIN的信号继承于UNIX系统,是不可靠信号

    10.可靠信号

    可靠信号支持未决信号排队克服了信号可能丢失的问题,linux后来添加的新信号(编号位于SIGRTMIN和SIGRTMAX之间)都是可靠信号

    11.实时信号和非实时信号

      实时信号为可靠信号,非实时信号为不可靠信号

    12.SIGCLD和SIGCHLD区别

    1)UNIX中,SIGCLD在被进程设置成捕捉后,内核会立刻检查在这之前是否已经有子进程终止了(等待着wait函数),如果有,则立刻调用捕捉函数,而SIGCHLD则不会做这个检查,只管之后的

    2)Linux中,SIGCLD等同于SIGCHLD

    13.kill函数和raise函数

    int kill(pid_t pid, int signo);
    int raise(int signo);

    kill函数将指定信号发送给指定进程(也可以是自身)进程组,raise函数只能将指定信号发给自身进程。

    13.1kill函数的pid

    1)pid>0 将信号传给进程标识码为pid 的进程

    2)pid=0 将信号传给和目前进程相同进程组的所有进程

    3)pid<0 将信号传给进程组识别码为pid 绝对值的所有进程

    4)pid=-1 将信号广播传送给系统内所有的进程

    13.2Linux中的kill指令

    1)Linux指令“kill pid”其实是向进程标识码为pid 的进程发送默认信号SIGTERM,因为SIGTERM信号编号为15,所以“kill pid”和“kill -s 15 pid”和“kill -15 pid”等价,“-s”可以省略,让“-”加在15上;

    2)进程收到SIGTERM信号,将会发生以下事情:进程释放相应资源后终止(类似于让进程正常退出);进程可能仍然继续运行;

    3)Linux指令“kill -s 9 pid”表示向进程发送SIGKILL信号来强制杀死进程;

    4)SIGTERM信号可以被捕捉和忽略,SIGKILL信号则不可以;

    5)Linux信号编号为0的信号为空信号,“kill -s 0 pid”常被用来确定一个指定pid的进程是否存在;

    14.alarm函数和pause函数

    unsigned int alarm(unsigned int seconds);
    int pause(void);

    1)alarm函数设置一个定时器,经过seconds定时器超时,会产生SIGALRM信号,此信号的默认动作是终止进程,一般将信号设置成捕捉,就可以实现相应的定时操作了;

    2)pause函数是进程挂起直到捕捉到某个信号,与alarm函数配合时只有当捕捉函数执行完,pause函数才释放进程;

    3)每个进程只能有一个闹钟时间,如果在调用alarm时,之前已经为该进程注册的定时器还没有超时,则这个定时器的剩余时间将会作为本次调用alarm的返回值,然后闹钟时间被更新:

    ret = alarm(5);
    sleep(3);
    
    ret = alarm(5);        //ret值为2,闹钟时间重新定成5s
    sleep(1);
    
    ret = alarm(5);        //ret值为4,闹钟时间重新定成5s

    15.常见信号

    1) SIGCHLD:一个进程终止时,SIGCHLD信号被送给其父进程

    2)SIGINT:中断信号,ctrl+c,用来中断进程

    3)SIGKILL(9):强制杀死任一进程,不可被捕捉和忽略

    4)SIGSTOP:一个作业控制信号,停止一个进程,不可被捕捉和忽略

    5)SIGTERM(15):kill命令默认的终止信号

    6)SIGPIPE:在读进程已终止时进行写操作,将产生此信号

  • 相关阅读:
    Go语言 插入排序并返回排序前的索引
    使用patch-package定制node_modules 中的依赖包
    移动端 rem自适应布局 (750的设计稿)
    通过原型截获input.value的方法
    ts 使用 keyof typeof
    logrotate日志管理工具
    【LeetCode刷题】239.滑动窗口最大值
    【LeetCode刷题】剑指Offer 48.最长不含重复字符的子字符串
    【LeetCode刷题】912. 排序数组
    【LeetCode刷题】744. 寻找比目标字母大的最小字母
  • 原文地址:https://www.cnblogs.com/Joezzz/p/9815748.html
Copyright © 2011-2022 走看看