Linux下进程及其相关概念理解

目录

何为进程?

task_struct 中存储了什么进程信息?

如何查看进程?

如何获取进程pid?

如何创建子进程?

为什么返回值如此呢?

为什么有两个返回值?

进程状态

进程的一般状态

运行态

终止态

阻塞态

挂起态

Linux下进程的状态(+表前台)

进程优先级

既然有优先级,那为什么需要运行队列排队呢?

基本概念


何为进程?

进程概念:正在执行的程序

对操作系统而言,OS要对进程做管理,OS用PCB(process control block)来描述进程,PCB是存储进程内部属性的内核数据结构,在Linux下,OS用struct task_struct结构体来描述进程。

在linux2.6源码中可以查到,sched.h中用task_struct描述进程

Linux下进程及其相关概念理解_第1张图片

 那么进程本质是什么呢?

进程本质是可执行程序和对应的内核数据结构。

task_struct 中存储了什么进程信息?

标识符(pid):进程在系统中的唯一标识符

状态:进程状态,退出码,退出信号

优先级:描述进程获取资源的先后顺序

程序计数器:程序将执行的下一条指令的地址

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

上下文数据:进程运行中CPU中寄存器存储的进程的相关数据

其他:进程的当前路径

如何查看进程?

1.命令:ps axj

比如使用 ps axj |head -1 &&  ps axj|grep ‘mytest’ |grep -v grep查看系统中的mytest进程

&& :逻辑与,前面命令执行成功了才执行后面的

2.在/proc 内存文件系统中查看当前系统实时的进程信息

Linux下进程及其相关概念理解_第2张图片

 当中蓝色数字是进程的pid,即每个进程在系统中的唯一标识符

进入对应进程文件可以看到

exe :进程对应的可执行程序的磁盘文件

cwd :进程当前的工作路径

如何获取进程pid?

1.使用系统调用getpid获取进程pid,使用getppid 获得父进程的pid

注意:几乎命令行上所有指令都是bash进程的子进程

2.使用ps axj命令查看,第二个数字是PID

当我们需要子进程协助父进程工作,或者希望子进程执行与父进程不同的功能的时候,需要创建子进程。

如何创建子进程?

使用fork函数(系统调用):

fork之后父子进程共享执行后续的代码,子进程继承父进程的数据,父子进程代码共享,数据各自独立。

Linux下进程及其相关概念理解_第3张图片

fork调用成功时,返回子进程pid给父进程,返回0给父进程,调用失败时返回-1

为什么返回值如此呢?

父进程必须有标识子进程的方案,fork之后给父进程返回子进程pid

子进程最重要的是知道自己创建成功,因为子进程找父进程的成本很低

不同返回值可以让不同进程执行不同的代码

为什么有两个返回值?

当OS在内核态执行fork函数准备返回的时候,子进程已经被创建,被OS放入运行队列中,又创建子进程之后父子进程共享执行后续的代码,所以有两个返回值,分别返回给父子进程。

运行队列:OS系统中描述进程运行的队列 struct runqueue{struct task struct *head;......},进程运行就是指进程在运行队列中被调度器调度

进程状态

Linux在PCB中用 int status描述。

进程的一般状态

这里描述的是一般概念,各个OS描述的进程状态不尽相同,但可由此延伸。

运行态

进程在运行队列中,准备就绪,随时可以调度,但不代表正在CPU上运行

终止态

进程还在,只不过永远不运行,随时等待被释放

为什么要维护终止态?不立马释放对应的资源?

释放资源需要花时间,当操作系统忙碌的时候,操作系统可能在处理别的任务,故不会立马释放资源。

阻塞态

        当进程申请CPU资源暂时无法得到满足,需要运行队列排队,申请其他慢设备同理,当进程需要访问某种非CPU资源时,该资源没有准备好,或者正在为其他进程提供服务,此时,进程要从运行队列移除,将当前进程放入对应设备描述结构体的等待队列中。

        当前进程正在等待某种(非CPU)资源,进程需要在该资源的等待队列中排队,进程的代码没有运行,进程所处的状态就是阻塞态。

挂起态

当内存不足的时候,操作系统要帮我们进行辗转腾挪,腾出内存空间来处理任务

如果进程短期内不会被调度,等待的资源短期内不会就绪,代码和数据依旧在内存中,会浪费空间,操作系统把进程的代码和数据置换到磁盘上,所以内存不足时往往伴随着磁盘被高频率访问。(注意:进程的PCB还在内存中)

Linux下进程的状态(+表前台)

R running运行态:同上,表示进程在运行队列中。

S sleeping:浅度睡眠,可中断睡眠,在阻塞等待非磁盘资源。

D disk sleep:与S类似不过等待的资源是磁盘资源,深度睡眠,不可被中断睡眠,os也无权杀死进程。

T stopped:暂停状态,比如给进程发送19号信号。

t tracing stop:暂停状态,与T类似,比如用gdb调试进程遇到断点的时候,程序就是t状态。

Z zombie:僵尸状态,进程退出时一般不会进入X状态,而是进入Z状态,因为进程一般需要将执行结果告知父进程或者OS,当子进程先退出时,父进程不退出也不等待,子进程会进入Z状态,如果没有人回收,该状态会被一直维护,会造成内存泄露。

X dead:死亡状态,表示进程资源可以马上回收。

S/D/T/t状态对应前面的是阻塞态或挂起态,Z和X对应前面的终止态。

孤儿进程:父进程先退出,被bash回收,子进程被1号进程(OS)领养,也即孤儿进程退出时会将退出信息返回给OS。

进程优先级

用于表示进程获取资源的先后顺序,之所以需要进程优先级,是因为系统的资源有限,需要进程以需要的一定顺序获取资源。Linux内核是抢占式内核,会发生进程抢占,也即正在运行的低优先级进程,如果来了个优先级更高的进程,调度器会直接把进程从CPU上剥离,放上优先级更高的进程。

Linnux下的优先级用PRI表示,用ps -al 查看进程信息,可以看到:

PRI越小表示优先级更高

PRI=80+nice值,nice值的取值范围是-20到19,可以使用top命令+r,再输入进程pid和更改后的nice值,来修改nice值,从而改变进程的优先级。
 

既然有优先级,那为什么需要运行队列排队呢?

        原因很简单,因为存在优先级一样的进程,Linux是通过进程优先级的队列来实现优先级的,使用 task_struct *queue[]指针数组实现不同优先级的队列,也即是多条链表去实现优先级,不同的数组下标就表示不同的优先级,通过位图标记不同优先级队列下是否有进程,这样就可以O(1)时间复杂度调度,不仅如此,Linux2.6内核用的是两张哈希表active和old去存储进程运行队列,新入的进程放入old表中,当CPU处理完active表后,交换两张表的底层指针,于是CPU又可以继续处理active表了。

基本概念

竞争性:因为进程数量众多,但CPU资源少量,所以进程之间具有竞争属性,即竞争性。为了高效完成任务,合理竞争相关资源,出现优先级。

独立性:多进程在运行,独享各种资源,运行期间互不干扰。

并行:多进程在多个CPU下分别同时运行。

并发:操作系统给每一个进程,在一次调度周期中赋予一个时间片的概念,每次进程执行一个时间片后进行进程切换,多个进程在一个CPU下采用进程切换的方式,在一段时间内,多个进程得以推进,进程串行运行,但宏观上我们感觉是并行运行,就称为并发。

进程的硬件上下文数据:CPU内的寄存器中保存进程运行时的临时数据,在进程剥离时保存,进程恢复时恢复。

你可能感兴趣的:(Linux,数据结构,linux)