zoukankan      html  css  js  c++  java
  • 任督二脉之进程管理(1)

    进程生命周期,进程生命周期创建、退出、停止,以及僵尸进程是什么意思。

    一、进程的定义

    进程--线程。进程是资源分配单位;搞清楚进程就是搞清楚进程资源情况。进程控制块PCB是OS的通用叫法。task_struct结构体描述进程的资源情况。如下图所属:

    1)*mm描述内存资源

    2)*fs:文件系统资源

    3)文件资源:注意与fs的区别,打开文件的fd数组fd_array记录打开文件的fd

    4)*signal:该进程的信号处理函数(用户理解为多态)

    5)pid:数量有限

    节选自《linux操作系统原理与应用》:

       传统上,这样的数据结构(task_struct)叫做进程控制块PCB。linux中PCB是一个相当庞大的结构体,其域多达80多项,它的所有域按其功能可分为以下几类:

    • 状态信息 描述进程的动态变化
    • 链接信息 描述进程的父子关系
    • 各种标识符 用简单数字对进程进行标识
    • 进程间通信信息 描述多个进程在同一任务 上的协作工作
    • 时间和定时器信息 描述进程在生命周期内使用CPU时间的统计、计费等信息
    • 调度信息 描述进程优先级、调度策略等信息
    • 文件系统信息 对进程使用文件情况进行记录
    • 虚拟内存信息 描述每个进程拥有的地址空间
    • 处理器环境信息 描述进程的执行环境(处理器的寄存器及堆栈等)

    二、pid

    1)pid数量有限,所以不能无限创建进程:32位-32768  64位-131072

    2)fork炸弹的原理

    改写一下代码

    1 :() #函数定义
    2 {
    3     :|:&  #调用自己,然后|管道,管道里面也递归调用:创建进程,然后&后台执行
    4 }
    5 ;  #函数结束
    6 :  #调用自己

    |是管道,&是后台执行。

    一直在创建进程,把pid耗尽,kill、killall等命令也要创建一个进程执行,但是pid已经耗尽,无法执行,用户感觉系统死掉。

     三、task_struct管理

    1)形成链表:最方便,但是进程之间的关系是树型关系,父子进程关系,pstree命令可以查看,所以也可以用树。

    zsh@zsh-vm:~$ pstree
    systemd─┬─ModemManager─┬─{gdbus}
            │              └─{gmain}
            ├─NetworkManager─┬─dhclient
            │                ├─dnsmasq
            │                ├─{gdbus}
            │                └─{gmain}
            ├─VGAuthService
            ├─accounts-daemon─┬─{gdbus}
            │                 └─{gmain}
            ├─acpid

    2)形成树:这样可以反应进程之间的关系,找父子关系比较简单,但是有时候需要检索一个进程的pid,比如 kill -2 8934,这种情况下树检索比较慢了。使用哈希可以快速查找

    3)形成哈希

    总结:快速遍历使用链表,想查找父子进程用树,想通过pid快速查找进程用哈希。所以linux里面这三种数据结构都有,使得各种场景快速达到目的,以空间换时间。

    四、进程生命周期

    1)就绪态:fork出来就是就绪态,linux里面就绪和运行的状态标志是一样的

    2)运行态:linux里面就绪和运行的状态标志是一样的,时间片用完或者被抢占进入就绪态

    3)睡眠态:等资源就进入睡眠态,等到资源就进入就绪态

    4)僵尸态:进程死掉先成为僵尸,用于描述task_struct及成员还没有消失,但是进程占用的资源已经消失;需要父进程wait4(waitpid等)等待僵尸才消失(父进程清理子进程)。所以僵尸状态是很短的。

    僵尸态的原因是父进程可以获取子进程的退出码exit_code,即退出原因。

    例子:杀死子进程,观察父进程能监控到子进程死亡原因。

     1 #include <stdio.h>
     2 #include <sys/wait.h>
     3 #include <stdlib.h>
     4 #include <unistd.h>
     5 
     6 int main()
     7 {
     8     pid_t pid, wait_pid;
     9     int status;
    10     
    11     pid = fork();
    12     
    13     if(pid == -1)
    14     {
    15         perror("Cannot create new process");
    16         exit(1);
    17     } else if (pid == 0)
    18     {
    19         printf("child process id: %ld
    ", (long)getpid());
    20         pause();
    21         _exit(0);
    22     } else 
    23     {
    24         #if 0 /* define 1 to make child always a zombie */
    25         printf("ppid: %d
    ", getpid());
    26         while(1);
    27         #endif
    28         do
    29         {
    30             wait_pid = waitpid(pid, &status, WUNTRACED | WCONTINUED);
    31             
    32             if(wait_pid == -1)
    33             {
    34                 perror("cannot using waitpid function");
    35                 exit(1);
    36             }
    37             
    38             if(WIFEXITED(status))
    39             {
    40                 printf("child process exits, status = %d
    ", WEXITSTATUS(status));
    41             }
    42             
    43             if(WIFSIGNALED(status))
    44             {
    45                 printf("child process is killed by signal %d
    ", WTERMSIG(status));
    46             }
    47             
    48             if(WIFSTOPPED(status))
    49             {
    50                 printf("child process is stopped by signal %d
    ", WSTOPSIG(status));
    51             }
    52             
    53             if(WIFCONTINUED(status))
    54             {
    55                 printf("child process resume running...
    ");
    56             }
    57             
    58         }while(!WIFEXITED(status) && !WIFSIGNALED(status));
    59         
    60         exit(0);
    61     }
    62 }
    View Code

    kill -9 pid是杀不死僵尸进程的,因为僵尸进程已经死掉了。父进程一直不清理僵尸进程,可以通过杀死僵尸进程的父进程来清理。

    僵尸进程的资源已经释放,所以不会造成内存泄漏。

    工程中观察进程是否内存泄漏:多点连续采样法。震荡收敛没有泄漏,震荡发散(上升)是内存泄漏。

    僵尸太多也不好,占用pid。

    5)停止态:人为停止进程,发送停止信号:1)ctrl+z,作业控制(JC),发送contine信号继续运行(fgg),kill发送信号等;2)GDB调试;

    cpulimit工具控制进程的cpu利用率:cpulimit -l 20 -p pid , 20为允许的cpu利用率,实际结果不会那么精

    确。

    五、 fork

    1)先看一个例子,fork叉子

    结果为打印6个(1*2+2*2):

    2)fork返回值:子进程返回0,父进程返回子进程的pid。

    运行结果:

     父子进程哪个先跑默认不确定,但是有内核可调试开关/proc,倾向于让子进程先跑。

    3)子死父清场:linux里面总是白发人送黑发人

    4)深度睡眠:必须等到资源才能醒,不响应信号,所以kill -9也杀不死。why?major page fault,代码段命运命中,还在硬盘,进程就进入深度睡眠,如果响应信号,那么信号处理函数有可能也在硬盘,没有载入内存,再次发生page fault,嵌套。中断响应吗?中断是正在执行被中断,已经睡眠了,怎么中断。

    时钟中断也不可以唤醒。

    浅度睡眠:资源来了醒,信号来了也可以醒。时钟中断可以唤醒。

     睡眠是内核调用进入,驱动也可以。用户态不可以直接调用睡眠。

    答疑:getppid()获取父进程的pid。

    书籍:operating system three piecies 全英文

    课后作业代码地址:

  • 相关阅读:
    hdu 1895 Sum Zero hash
    hdu 4277 USACO ORZ dfs+hash
    hdu 6010 Daylight Saving Time 泰勒公式
    Codeforces Round #FF (Div. 2) D. DZY Loves Modification 优先队列
    Codeforces Round #113 (Div. 2) B. Polygons Andrew求凸包
    poj 3304 Segments 线段与直线相交
    gym 101081 gym F. Auction of Services 最小生成树+倍增LCA
    hdu 1558 Segment set 线段相交+并查集
    gym 101081 E. Polish Fortress 几何
    SPOJ
  • 原文地址:https://www.cnblogs.com/shihuvini/p/8413189.html
Copyright © 2011-2022 走看看