入门Linux 进程:进程概念、进程状态与进程地址空间
目录
0.写在前面
1.什么是进程?
2.如何查看进程?
3.进程信息有什么?
4.进程的一些性质
5.拓展:进程上下文
0.写在前面
本文将对Linux环境下的进程:包括进程概念,进程状态以及进程地址空间进行讲解,作者使用XShell连接配置为CentOs 7.6的主机进行演示,希望能帮助你更好理解操作系统的运行原理!
1.什么是进程?
在了解进程之前,先来说一说操作系统是如何管理数据的:这里打个比方,将操作系统当作老板,当软硬件当作员工,那么老板如何管理员工?是直接管理吗?当然不是,老板当然不会直接和员工接触通常在它们两者之间存在部门经理或者部门主管,而一般都是通过部门主管根据老板的指令来管理员工,这也就说明了操作系统是不可以直接管理硬件的,而是通过中间充当部门主管的驱动程序,来间接管理硬件。
总结:通过驱动程序来读取硬件的数据,再将数据传给操作系统进行管理。
那么有了数据操作系统又是如何管理的呢?这里就要经历一个先描述再组织的过程,那么什么是描述什么是组织呢?假设你要写一个学生管理系统,是不是先要创建一个结构体来存放学生的各种信息,包括他的学号、性别、年龄,然后再选择一个恰当的数据结构管理这个结构体,这样一个处理数据的过程在操作系统中同样适用,这里创建一个结构体的过程就叫做描述,而选择一个数据结构来管理这个结构体的过程就叫做组织。我们通常不能直接访问操作系统中的这些数据,但是如果我们要使用这些数据可以通过操作系统提供的系统接口来进行访问,通过接口来进行访问这些数据就叫做系统调用。
总结:数据要通过先描述:创建结构体,再组织:通过数据结构管理,这样管理数据就是对数据结构的增删查改。
在了解了上面这些之后,我们正式引入进程的概念:
进程(Process):一个已经加载到内存中的程序,就叫做进程。它是操作系统进行资源分配和调度的基本单位,拥有独立的运行环境、内存空间和系统资源(如 CPU、文件句柄、网络连接等)。
举例:双击桌面的浏览器图标,磁盘上的浏览器程序被加载到内存,形成一个浏览器进程;再次打开浏览器,会创建第二个进程(即使程序相同,进程也相互独立)。
这里的进程是内存中的程序,先来解释一下为什么程序要从磁盘加载到内存中吧:根据冯诺依曼体系结构,由控制器和运算器组成的CPU中央处理器不可以直接和磁盘上的数据进行接触,而只能和内存进行写入和读取,这是因为读写速度差距太大的原因,我们把程序也当做一种数据,那么程序只能加载到内存当中运行。既然是数据那么就要经历先描述再组织的过程:描述时定义的结构体,称之为PCB,进程控制块(process control block),其中包含的是进程属性的集合,(当属性足够多,属性的集合就是目标对象),由于都是C写的,所以在Linux中就是struct结构体来储存进程的属性信息,其中,struct包含进程编号,进程状态,以及优先级etc.
但是单单具有进程控制块PCB还不足以称之为进程,一个完整的进程:需要包括一个PCB和它对应的代码数据。
总结:进程=内核PCB数据结构对象+你自己的代码和数据,操作系统管理时不会管理代码和数据,而是管理内核PCB数据结构,PCB中存在指针指向代码数据,先描述——创建PCB,再组织——将PCB转化为双向链表(数据结构)进行增删查改。
不同的操作系统上PCB名称不同,在Linux中叫task_struct,是一种数据类型,包含进程的所有属性,包括但不限于:
标识符、状态、优先级:相对于其他进程的优先级、程序计数器:记录程序中即将被执行的下一条指令的地址,方便程序被唤醒时重新执行、内存指针:记录代码数据在内存中的存储地址、上下文数据、 I/O状态信息、记账信息。
2.如何查看进程?
在Linux环境下我们如何来查看进程呢?
查看进程:ls /proc/PID,Linux会将进程写入到proc这个目录下,每个PID又对应不同PCB,其中有task_struct属性
显示进程信息:ps ajx | head -1 && ps ajx | grep 文件名 也可以是 ps -al |head -1 && ps -al | grep 文件名 还可以是top
如果需要会话 / 组关联关系,ps ajx 合适;如果需要进程的优先级、内存占用信息,ps -al 更合适(ps实际上实在遍历结点为PCB的双链表,将信息遍历打印出来)
结束进程:kill -9 PID
top进程查看:
ps ajx | head -1 && ps ajx | grep 文件名 / ps -al |head -1 && ps -al | grep 文件名查看:
ls /proc/PID查看:
学会了查看进程,下面来看看进程信息有哪些?
3.进程信息有什么?
为了了解进行信息,我们可以打印出查看:
可以看到,进程有PPID,PID,PGID,SID,TTY,TPGID,STAT,UID,PRI,NI这些主要的信息,作者将选取一部分常用的进行讲解:
标识符: PID:process ID,这是进程的ID;
PPID: 父进程的process ID,一般为bash(命令行解释器),会为命令创建一个子进程,重新执行子进程,只有子进程的PID改变,PPID不变;
进程状态:STAT,什么是进程状态?进程状态是操作系统对进程当前运行状态的抽象描述,记录在进程控制块中,用于调度器决策(如是否分配 CPU 时间片)和资源管理。操作系统一共可以分为三种状态:
运行态:在运行队列(rq)的状态:在一个时间段内所有的进程代码都会被执行(并发执行),进程大量放入CPU大量拿出CPU的过程叫做(进程切换),并且一个进程不可能无限运行下去,时间片会规定一个进程所能运行的时间,时间片用完则回到运行队列尾部,重新排队,每一个CPU都会有一个运行队列。
在单 CPU 情况下,多个进程看似同时运行,实则是轮番穿插执行。操作系统按一定策略,定期给每个进程执行机会,每次仅运行一小段时间(即一个时间片)。由于时间片通常极短(如 Linux 系统中为 5ms-800ms),进程切换迅速,用户几乎察觉不到,从而产生多进程同时运行的 “假象”。例如,一边用浏览器下载文件,一边用音乐播放器听音乐,就是通过时间片机制实现的。
阻塞态:每个设备都有一个等待队列(wq),当这个设备需要的资源没有拿到时,进程状态会从运行态改为阻塞态,设备的等待队列会连接PCB,此时进程不参与 CPU 调度(不在运行队列中),直到被唤醒。(所谓唤醒,就是将状态改为运行态并移交给运行队列)
挂起态:操作系统由于内存不足,将空闲资源的代码数据移交磁盘而只保留PCB的状态,(如果拿出了代码数据后内存还是不足,那么操作系统会杀死进程)
对应到Linux中的具体进程状态:
R Running可以对应到运行态,后面+代表前台运行,没有+代表在后台运行,运行时加上&可以放于后台运行
S Sleeping可以对应到阻塞态,当printf时CPU会等待输入到外设中,两者速度相差太大,为S状态,其他情景中当等待数据就绪时也会是阻塞状态(S态)
D Disk sleep 首先S可以理解为浅度睡眠,当内存资源严重不足的时候并且没有可以移动的代码数据时,操作系统会将处于S状态的进程杀掉,而普通用户也可以杀掉S进程,但是如果这个进程进行着将数据输入到磁盘的任务时,杀掉就会导致数据丢失,为了防止数据丢失,进程状态必须设置为D,处于D状态的进程不能被用户或者操作系统杀掉,不会响应任何请求
T/t stop 暂停状态,表示当前进程暂停运行,暂停和继续一个进程可以使用kill命令: 9) SIGKILL 18) SIGCONT 19) SIGSTOP,T和S其实是有一定的区别的,S可以代表等待资源就绪,而T不一定是因为资源的问题而暂停的,t可以是调试时遇到断点而暂停的
X dead 死亡状态,进程已经结束力或者被杀掉了,由于X状态是瞬时的,不方便演示
Z 僵尸状态,当一个子进程执行完毕(正常退出或异常终止)后,其PCB不会立即被销毁,而是会保留一段时间,等待父进程通过 wait() 或 waitpid() 系统调用来获取其终止状态(如退出码、信号信息等),等待的这个过程中,子进程的状态为僵尸状态。之后会变为X死亡状态,如果父进程没有对子进程的资源进行释放,处于僵尸进程的子进程没有被处理,就会造成内存泄露!如果是父进程先退出,那么子进程的父进程会被改成1号进程(就是操作系统本身),子进程变为孤儿进程,被OS领养
优先级:PRI,为什么要存在优先级:因为资源是有限的,进程有多个注定进程之间是竞争关系,操作系统必须保证进程之间良性竞争,需要确认优先级,如果进程长时间得不到CPU资源,该进程的代码长时间无法得到推进,这就会引发进程的饥饿问题。
如果要查看有关于优先级PRI的信息,命令:ps -al |head -1 && ps -al | grep 文件名:
其中PRI是优先级priority,NI是nice值:代表进程优先级的修正数据,用户可以修改nice值来调整优先级顺序,优先级的值=PRI+NI;值越小优先级越高,由于Linux不想过多让用户修改优先级,nice有一个范围 [-20,19]
修改命令:nice/renice/top ->r->PID->nice 每次设置PRI(new)=PRI(原先值)+nice(new)
4.进程的一些性质
竞争性:多个进程之间存在竞争关系
独立性:多个进程之间互不影响
并行:多个进程在多个CPU同时进行运行
并发:多个进程在一个CPU采用进程切换方式,在一段时间之内,让多个进程都可以推进,可以结合前面内核调度器的思想,在一个优先级最高的进程运行完时间片之后,会到另一个空指针数组中进行排队,这样保证其他的进程可以正常运行
5.拓展:进程上下文
什么是进程上下文?一个进程运行时会产生很多临时数据存储在CPU的寄存器中,而寄存器保存的与进程相关的临时数据就称为进程上下文。
常见的寄存器有:
程序计数器(PC):指向下一条要执行的指令地址(决定 “从哪里继续执行”),通常由寄存器eip保存
通用寄存器(如eax,ebx,ecx,edx):保存函数参数、局部变量
状态寄存器(status):保存进位标志、零标志、中断允许标志等
栈指针(栈帧)(ebp,esp,eip):指向当前栈顶位置(决定 “函数调用栈的状态”)
进程在被切换的时候会保存上下文到PCB中以及恢复上下文到寄存器中,当进程被暂停(如 CPU 调度切换)或从休眠唤醒时,内核通过保存或恢复上下文,使进程得以继续进行。