0


Linux 进程基础概念详解

一.基本概念

1.进程

通俗的观念:程序的一个执行实例,或正在执行的程序。
内核的观点:担当分配系统资源(CPU时间和内存)的实体。

2.进程控制块-PCB

进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。

3.Linux中的PCB

Linux操作系统下的PCB是:task_struct。task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息。

二.进程信息

使用 ps aux 命令可以查看进程,如下:

进程信息也可以进入/proc 系统文件夹查看:

那么如何查看我们自己写的代码被加载到内存后的进程信息?先来看如下代码:

这两种方法都可以,查到进程的进程号。

要查看自己写的代码进程信息,首先要保证代码的运行时间够长,如果运行时间太短,那么查看时进程就已经退出,查看不到了。以上代码中我使用了死循环,将test.c文件进行编译生成test文件运行后,使用命令 ps aux | grep mytest 就可以查看到进程信息。如果要停止运行,在执行的界面输入:Ctrl+c 就可以结束当前进程。

注意:只有代码在运行的时候,才能看到进程。

三.PID的获取

描述本进程的唯一标示符(PID),用来区别其他进程。创建任何进程时,它都有一个唯一的ID,称为其进程ID。有两个系统调用函数用于获取进程ID,这些函数是:
1.getpid()

它的返回值就是当前进程的PID,当代码运行起来后,PID被打印出来,结果与用命令 ps aux | grep test 查看到的结果一致。

2.getppid()

它的的返回值是当前进程的父进程的PID,与getpid()功能类似。

四.进程的三种状态

站在CPU的角度,进程状态可以分为:运行、就绪、阻塞。

运行:进程占用CPU,正在使用CPU来执行自己的代码

就绪:进程已经具备运行条件,但是CPU没有分配过来。

阻塞:进程等待某种资源,而不能运行。例如:等待IO输入。

用一幅图来直观的理解:

五.细分的七中进程状态

1.R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。来看如下代码:

代码是死循环,并且什么都不做,当程序运行起来后CPU的占用率非常高,此时当前进程就是运行状态。
2.S 可中断睡眠睡眠状态(sleeping): 意味着进程在等待事件完成。
如下代码:

3. D 不可中断睡眠状态休眠状态,在这个状态的进程通常会等待IO的结束。此状态难以模拟。

4.T停止状态(stopped): 可以通过ctrl + z 暂停这个进程。这个被暂停的进程可以通过发送 f+g 让进程继续运行。

5.t跟踪状态:调试程序的时候可以看到。

如下代码,编译时加上-g选项后,生成可调式的test文件,使用gdb调试,打上断点,让程序运行起来,然后查看进程状态,就可以看得到了。

6.X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。

7.僵尸状态(Zombies)是一个比较特殊的状态。当进程退出,并且父进程没有读取到子进程退出的返回代码时,就会产生僵尸进程。

六.进程的内部

1.程序计数器

作用:保存程序中即将被执行的下一条指令的地址。

一个进程不一定一直占用CPU资源,当代码没有执行完时,可能会被从CPU当中剥离出来,将CPU资源让其他进程使用,当再一次拥有CPU资源后,程序计数器的作用就体现了,代码可以从上一次中断的位置开始执行。

2.上下文信息

作用:保存进程执行时处理器的寄存器中的数据。

当进程切换时,保存数据,为下一次在执行做准备。

3.内存指针

内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。

4.IO信息

I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。

记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。

七.fork创建子进程

fork()的头文件 #include<unistd.h>
fork是用来创建子进程的:

创建成功:返回两次值,往父进程返回一次值,往子进程返回一次值。

          返回给父进程的值 >  0

          返回给子进程的值 = 0

创建不成功:返回 -1

1.代码模拟


可以发现,fork()返回给父进程的值是子进程的PID。

2.原理

1.子进程拷贝父进程的PCB

2.父子进程代码共享

3.数据独有 (各有各的进程地址空间)

注意:父子进程在运行的时侯需要独享各种资源,各自拥有自己的进程地址空间。互相执行时,数据不会互相干扰。子进程的代码是从fork()之后开始执行的,不执行fork()语句。主要依靠程序计数器来完成。

八.僵尸进程

1.僵尸进程的产生

僵尸体状态(Zombies)是一个比较特殊的状态。当子进程退出,并且父进程没有读取到子进程退出的返回代码时,就会产生僵尸进程。

2.僵尸进程产生的原因

子进程在退出的时候,会告诉父进程,父进程忽略处理,父进程并没有回收子进程的退出状态信息。所以子进程的PCB没有释放。形成僵尸进程。

3.代码模拟

如下代码中,子进程先于父进程退出,父进程并没有回收子进程的退出状态信息,子进程就变成了僵尸进程,状态为僵尸状态(Z+)。

4.僵尸进程的危害

子进程的PCB一直得不到释放,从而造成了内存泄漏。

程序员针对僵尸进程,无法使用kill命令杀死进程,造成内存泄漏,如果一个系统里面僵尸太多,浪费的资源就特别大。

5.解决方案

1.杀死父进程(不推荐)

2.重启操作系统(不推荐)

3.进程等待(属于进程控制章节)

九.孤儿进程

1.孤儿进程的产生

父进程先于子进程退出,子进程就称之为"孤儿进程"。

2.代码模拟

如下代码中,父进程先退出,子进程变成了孤儿进程,后被1号进程领养。

注意:可以使用 kill 命令杀掉孤儿进程,但是本能杀死僵尸进程。

kill + 孤儿进程(PID)。

切记:没有孤儿状态(孤儿进程它的状态是S )孤儿进程没有危害 。

    :孤儿进程的父进程是1,它被1进程收留。它的内存也能得到合理释放,没有危害。

十.问题回答

问题1:父进程子进程 谁先执行?

答:一旦父进程将子进程创建出来,父子进程也是抢占式执行,没有规定,一定谁先执行。

问题2:什么是1号进程?

答:/usr/lib/systemd/systemd : 操作系统启动的第一个程序,或许很多进程都是这个进程创建创建的,或者是由它的子进程创建出来的操作系统初始化的一些工作,操作系统就是一个软件(也就是一堆代码)。

问题3:正常在命令行中启动的程序,他的父进程是谁?

答:bash ./mytest 这里的./ 是告诉bash 我们要执行的程序在那个地方。

问题4:fork()调用子进程,子进程中的内容是对父进程的拷贝,会不会出现无限调用子程序的情况出现?

答:不会,子程序对于代码只能从fork()的下一行代码执行。不会再出现调用子程序。

问题5:S+ R+ 后面的+ 是什么意思?

答:+表示此时它是一个前台进程,阻塞bash,让bash不能处理其它问题。没有+就变成了后台进程,只能在后台运行。

标签: linux 运维 服务器

本文转载自: https://blog.csdn.net/weixin_53332395/article/details/123299591
版权归原作者 C++七星瓢虫 所有, 如有侵权,请联系我们删除。

“Linux 进程基础概念详解”的评论:

还没有评论