zoukankan      html  css  js  c++  java
  • 僵尸进程学习 & 进程状态列表 & Linux信号学习

    参考这篇文章:

    http://www.mike.org.cn/articles/treatment-of-zombie-processes-under-linux/

    在Linux进程的状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。它需要它的父进程来为它收尸。

    如果他的父进程没安装SIGCHLD信号处理函数,也没有调用wait或waitpid()等待子进程结束,又没有显式忽略该信号,那么它就一直保持僵尸状态,如果这时父进程结束了,那么init进程自动会接手这个子进程,为它收尸,它还是能被清除的。

    僵尸进程的避免

      1、父进程通过wait和waitpid等函数等待子进程结束,这会导致父进程挂起

      2、如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler,因为子进程结束后,父进程会收到该信号,可以在handler中调用wait回收

      3、如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCHLD, SIG_IGN) 通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收,并不再给父进程发送信号

      4、还有一些技巧,就是fork两次,父进程fork一个子进程,然后继续工作,子进程fork一个孙进程后退出,那么孙进程被init接管,孙进程结束后,init会回收。不过子进程的回收还要自己做。

    子进程结束后为什么要进入僵尸状态?

      因为父进程可能要取得子进程的退出状态等信息。

    S(state of the process )

      O:进程正在处理器运行 
      S:休眠状态(sleeping)
      R:等待运行(runable)   
      I:空闲状态(idle)
      Z:僵尸状态(zombie)   
      T:跟踪状态(Traced)
      B:进程正在等待更多的内存页
      C:cpu利用率的估算值(cpu usage)

    SIGCHLD信号(17),该信号的默认处理动作是忽略

    事实上,由于UNIX的历史原因,要想不产生僵尸进程还有另外一种办法:父进程调用sigaction将SIGCHLD的处理动作置为SIG_IGN,这样fork出来的子进程在终止时会自动清理掉,不会产生僵尸进程,也不会通知父进程。系统默认的忽略动作和用户用sigaction函数自定义的忽略通常是没有区别的,但这是一个特例。此方法对于Linux可用,但不保证在其它UNIX系统上都可用。请编写程序验证这样做不会产生僵尸进程。

    kill -18 PPID (SIGCONT, PPID是其父进程)

    这个信号是告诉父进程,该子进程已经死亡了,请收回分配给他的资源。(没实验过,不确定)

    SIGCONT也是一个有意思的信号。如前所述,当进程停止的时候,这个信号用来告诉进程恢复运行。该信号的有趣的地方在于:它不能被忽略或阻塞,但可以被捕获。缺省行为是丢弃该信号。

    3. kill默认发的是 SIGTERM,也就是15. 

    全部信号的列表如下:

    $ 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 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

    各种信号的处理方式可以参考这个网页:http://blog.chinaunix.net/uid-11848011-id-96416.html

    对信号的三种处理方式

    1、忽略此信号:大多数信号都可使用这种方式进行处理,但有两种信号却决不能被忽略。它们是:SIGKILL 和 SIGSTOP。这两种信号不能被忽略的,原因是:它们向超级用户提供一种使进程终止或停止的可靠方法。另外,如果忽略某些由硬件异常产生的信号(例如非法存储访问或除以0),则进程的行为是示定义的。

    2、直接执行进程对于该信号的默认动作

    3、捕捉信号:执行自定义动作(使用signal函数),为了做到这一点要通知内核在某种信号发生时,调用一个用户函数handler。在用户函数中,可执行用户希望对这种事件进行的处理。注意,不能捕捉SIGKILLSIGSTOP信号。

    Ctrl-c产生SIGINT信号,Ctrl-产生SIGQUIT信号,Ctrl-z产生SIGTSTP信号

    内核实现信号捕捉的步骤:

          1、用户为某信号注册一个信号处理函数sighandler

          2、当前正在执行主程序,这时候因为中断、异常或系统调用进入内核态。

          3、在处理完异常要返回用户态的主程序之前,检查到有信号未处理,并发现该信号需要按照用户自定义的函数来处理。

          4、内核决定返回用户态执行sighandler函数,而不是恢复main函数的上下文继续执行!sighandlermain函数使用的是不同的堆栈空间,它们之间不存在调用和被调用的关系,是两个独立的控制流程)

          5、sighandler函数返回后,执行特殊的系统调用sigreturn从用户态回到内核态

          6、检查是否还有其它信号需要递达,如果没有 则返回用户态并恢复主程序的上下文信息继续执行。

  • 相关阅读:
    STM32 时钟配置分析
    STM32 开发板资源梳理
    STM32 摄像头实验OV2640
    STM32 TFT液晶屏与FSMC
    STM32 开发板电源与供电方式
    视觉里程计07 Qt的一些bug修改记录
    解决wireshark检测不到网卡的问题
    gdb 脚本调试
    [转] GCC 中的编译器堆栈保护技术
    使用gdbserver远程调试
  • 原文地址:https://www.cnblogs.com/charlesblc/p/6213368.html
Copyright © 2011-2022 走看看