任督二脉之进程管理(1)

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

1、进程的定义数组

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

1)*mm描述内存资源ide

2)*fs:文件系统资源函数

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

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

5)pid:数量有限操作系统

节选自《linux操做系统原理与应用》:线程

   传统上,这样的数据结构(task_struct)叫作进程控制块PCB。linux中PCB是一个至关庞大的结构体,其域多达80多项,它的全部域按其功能可分为如下几类:3d

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

2、pid

1)pid数量有限,因此不能无限建立进程:32位-32768  64位-131072

2)fork炸弹的原理

改写一下代码

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

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

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

 3、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里面这三种数据结构都有,使得各类场景快速达到目的,以空间换时间。

 

4、进程生命周期

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\n", (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\n", 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\n", WEXITSTATUS(status));
41             }
42             
43             if(WIFSIGNALED(status))
44             {
45                 printf("child process is killed by signal %d\n", WTERMSIG(status));
46             }
47             
48             if(WIFSTOPPED(status))
49             {
50                 printf("child process is stopped by signal %d\n", WSTOPSIG(status));
51             }
52             
53             if(WIFCONTINUED(status))
54             {
55                 printf("child process resume running...\n");
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信号继续运行(fg\bg),kill发送信号等;2)GDB调试;

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

确。

 

5、 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 全英文

课后做业代码地址:

相关文章
相关标签/搜索