建设执业资格注册管理中心网站网站建设的职称
- 作者: 五速梦信息网
- 时间: 2026年04月20日 10:41
当前位置: 首页 > news >正文
建设执业资格注册管理中心网站,网站建设的职称,seo网站制作,wordpress 教程 知乎文章目录一、什么是进程1.进程概念2.进程描述 – PCB3.task_struct内容分类二、进程的基本操作1.查看进程2.结束进程3.通过系统调用获取进程标示符4.通过系统调用创建子进程(fork)三、进程状态1.普遍的操作系统状态2.Linux操作系统状态四、两种特殊的进程1.僵尸进程2.孤儿进程五… 文章目录一、什么是进程1.进程概念2.进程描述 – PCB3.task_struct内容分类二、进程的基本操作1.查看进程2.结束进程3.通过系统调用获取进程标示符4.通过系统调用创建子进程(fork)三、进程状态1.普遍的操作系统状态2.Linux操作系统状态四、两种特殊的进程1.僵尸进程2.孤儿进程五、进程优先级1.基本概念2.查看系统进程3.PRI and NI4.查看进程优先级信息5.通过top命令修改进程优先级ni六、进程的其他概念七、进程切换一、什么是进程 1.进程概念 课本概念程序的一个执行实例正在执行的程序等或者进程就是被加载到内存中的程序或者被运行起来的程序就叫做进程 内核观点担当分配系统资源CPU时间内存的实体。 严格意义上的进程 进程对应的磁盘代码(可执行程序代码) 该进程对应的内核数据结构(task_struct) 假设你在磁盘上写了一个名为bin.c的文件代码最终经过编译链接形成bin.exe可执行程序。这个可执行程序是一个文件当前存放在磁盘中根据冯诺依曼体系得知磁盘就是一个外设你的程序最终要被CPU运行要先从外设磁盘加载到内存中而加载的过程就叫做此程序运行起来了但是这不能说是进程这个程序只是搬到内存依旧是个程序。 2.进程描述 – PCB 操作系统里面可能同时存在大量被加载的进程 操作系统要将所有的进程管理起来而对进程的管理本质就是对进程数据的管理依旧是先描述再组织。下面分开讨论 先描述 所以当一个程序加载到内存时除了加载了代码和相关数据操作系统还要为了管理该进程创建了对应的数据结构。而Linux操作系统描述进程是用一个叫task_struct的结构体进程的所有属性数据全部放在这个结构体中task_struct每一个结构体指向对应的磁盘代码当我们有多个进程的时候也相应的要匹配多个task_struct结构体。此时描述好后还需要再组织起来 再组织 这里我们把所有的task_struct用双链表链接起来即可此时对进程的管理就变成了对内核数据结构PCB的相关管理也就是对链表进行增删查改转化成了对进程的管理。 而在操作系统里我们把描述进程的结构体叫做PCBprocess control block 进程控制块而Linux下的进程控制块叫做struct task_struct以此来描述进程结构体。task_struct是Linux内核的一种数据结构它会被装载到RAM内存里并且包含进程的信息。通过内核结构体我们能够创建出内核对象将该结构和我们的代码和数据相关联起来就完成了先描述在组织的工作。 抽象出来可以用如下结构体来表示 (假设task_struct使用链表进行组织) struct task_struct { //进程的所有属性… …//进程对应的代码和数据的地址… …//下一个进程的地址struct task_struct* next; };Linux系统中task_struct的代码 注关于 task_struct 的详细介绍即其中包含了那些具体的进程属性可以参考下面这篇文章Linux中进程控制块PCB——-task_struct结构体结构 。 综上我们就从操作系统内核的观点来理解进程进程 内核数据结构 (task_struct) 进程对应的磁盘代码。 3.task_struct内容分类 task_struct就是Linux当中的进程控制块task_struct当中主要包含以下信息 标示符 描述本进程的唯一标示符用来区别其他进程。状态 任务状态退出代码退出信号等。优先级 相对于其他进程的优先级。程序计数器(pc) 程序中即将被执行的下一条指令的地址。内存指针 包括程序代码和进程相关数据的指针还有和其他进程共享的内存块的指针。上下文数据 进程执行时处理器的寄存器中的数据。I/O状态信息 包括显示的I/O请求分配给进程的I/O设备和被进程使用的文件列表。记账信息 可能包括处理器时间总和使用的时钟总和时间限制记账号等。其他信息 二、进程的基本操作 1.查看进程 假设我现在生成了一个可执行程序myproc它现在位于磁盘上现在我们将程序运行起来此时这个程序就变成了一个进程。 我们该如何查看现在的进程呢主要有下列几种办法 通过ps命令查看进程通过proc查看 下面逐个分析 通过ps命令查看进程 ps ajx | grep myprocps ajx命令会把你系统中所有的进程显示出来随后我们使用管道命令组合grep为的是把名为myproc的进程显示出来如下 明明要的是myproc进程为什么会出现grep的进程呢 我们自己写的代码编译成为可执行程序启动之后就是一个进程同样别人写的代码启动之后也是一个进程。例如先前学到的ls、pwd、touch、grep、chgrp……指令这些指令就是别人写的存在目录/usr/bin/中 这些指令在执行后也会成为进程这也就是为什么上面会把grep显示出来。 如何只显示mytest进程呢 输入下面的命令 ps ajx | grep myproc | grep -v grep此命令就是把带有grep字符的进程屏蔽掉此时展现出来的就是我mytest进程。 通过proc查看 我们都清楚根目录下有很多的路径 注意上面的proc目录它是一个内存文件系统里面放的是当前系统实时的进程信息。我们进入此目录看看 每一个进程在系统中都会存在一个唯一的标识符就如同每个学生都有学号一样而这个唯一标识符在linux称为pid全称process id而上面蓝色的数字即为进程的pid。 我们可以查看你显示出来的所有的title列名称输入下面的指令 ps ajx | head -1这一行显示的就是所有的属性名提取好了属性下面继续往后显示mytest的进程直接使用逻辑与操作 ps ajx | head -1 ps ajx | grep mytest | grep -v grep前面又得知proc存放的是当前系统实时的进程信息现如今我们已然得知进程mytest的pid8666下面就在proc目录里面查询一下 而如果我们 [CtrlC] 停止myproc的运行根据proc是实时显示进程的性质它此时就不会再显示进程myproc了 而当我们再次运行起myproc程序时再使用刚才的命令结果如下 此时会发现先前的pid失效了由此得知重新启动程序就叫做一个新的进程会给你重新分配一个pid。 补充1如何理解当前路径 下面输入这条指令并从中截取这块内容。 ls /proc/15243 -alcwd表示进程当前的工作路径。exe表示进程对应的可执行程序的磁盘文件。 先前我们学习文件操作时知道如果我用fopen创建一个文件它默认是在当前路径而当前路径指的就是当前进程所在路径进程自己会维护。 补充2pid当前路径这些都是进程的内部属性。都在进程的进程控制块PCBtask_struct结构体中 2.结束进程 对于一个进程来说我们可以使用 [Ctrl c] 来结束进程也可以使用 kill 命名指定 -9 选项来结束。 这里我们可以进入进程PID我们这里思考一个问题当我们删掉正在执行进程对应的可执行文件的时候进程是否会停止/退出 答案是不会我们知道可执行文件被加载到内存中CPU会执行相应的代码形成进程。进程形成时不会被对应的可执行文件所影响。但是如果我们【Ctrl c】停止进程这时进程的PID已经消失了。 3.通过系统调用获取进程标示符 我们可以通过使用操作系统给我们提供的系统调用接口 getpid() 与 getppid() 来获取进程id和父进程id (进程ID是一个进程的唯一标识)。这里的返回值pid_t大家把它当做int就行打印的时候使用%d即可。 我们通过如下程序打印进程和父进程ID #include stdio.h #include unistd.h #include sys/types.hint main() {while(1){printf(我是一个进程我的ID是%d我的父进程ID是%d\n, getpid(), getppid());sleep(1);}return 0; }运行该程序即可获得该进程的pid和ppid 我们下面可以通过ps命令查看该进程的相关信息 补充1如何杀掉进程 1、按下【Ctrl c】2、使用命令【kill -9 pid】 补充2父进程ppid是不会变的 前面我们得知我们每次重新运行一个进程其pid是会不断变化的可是父进程ppid是不会变的。这是因为进程的代码和数据需要重新从磁盘中加载但是它的父进程id是通过 bash 来执行。bash是shell外壳并不会变化。 我们可以输入下面的指令来查看这个父进程到底是什么 ps ajx | head -1 ps ajx | grep 28297图中可以看出父进程28297就是一个bash即 shell 外壳这也侧面证实了我们在 Linux权限管理 中提到的结论shell 为了防止自身崩溃并不会自己去执行指令而是会派生子进程去执行。几乎我们在命令行上所执行的所有的指令都是bash进程的子进程 4.通过系统调用创建子进程(fork) fork函数是用来创建子进程的它有两个返回值 返回成功的话把子进程的pid返回给父进程给子进程返回0失败的话-1返回给父进程。不创建子进程 因为其有两个返回值这导致我一个printf语句运行后会输出两个并且返回的值一个为子进程的pid给父进程一个0给子进程。 根据上面得知既然父进程和子进程获取到fork函数的返回值不同那么我们就可以据此来让父子进程执行不同的代码从而做不同的事。示例 #include stdio.h #include unistd.h #include sys/types.hint main() {pid_t id fork();if(id 0){while(1){printf(子进程pid:%d, ppid:%d, id:%d\n, getpid(), getppid(), id);sleep(1);}}else if(id 0){while(1){printf(父进程pid:%d, ppid:%d, id:%d\n, getpid(), getppid(), id);sleep(1);}}else {printf(子进程创建失败!\n);}return 0; }由上图得知子进程为10461父进程为10460父进程的父进程为25316此外我们还可以发现这里的if 和 else语句竟然可以同时执行。 总结 fork之后父进程和子进程会共享代码一般都会执行后续的代码这就是为什么printf会打印两次的原因。fork之后父进程和子进程返回值不同可以通过不同的返回值判断让父子执行不同的代码块。 补充1fork()为什么给父进程返回子进程的pid给子进程返回0 父进程必须有标识子进程的方案这个方案就是fork之后给父进程返回子进程的pid子进程最重要的是要知道自己被创建成功了因为子进程找父进程成本非常低只需要getppid()即可所以只需要给子进程返回0即可。 补充2为什么fork会返回两次 fork是用来创建子进程则会导致系统多了一个进程task_struct子进程的代码和数据子进程的task_struct对象内部的数据大部分从父进程继承下来的。子进程和父进程执行同样的代码fork之后父子进程代码共享而数据要各自独立。虽然代码共享但是可以让不同的返回值执行不同的代码。调用一个函数当这个函数准备return的时候这个函数的核心功能已经完成子进程已经被创建了并将子进程放入运行队列现在父进程和子进程既然都存在并且代码共享那么当然return要返回两次。自然就有两个返回值。 三、进程状态 1、 什么是进程状态 我们知道一个程序被加载到内存变成进程之后操作系统要对该进程进行管理即为其创建对应的PCB对象。而进程状态本质上就是PCB内部的一个整形变量不同的整形值就对应不同的进程状态。 2、进程有什么状态 状态反映进程执行过程的变化。这些状态随着进程的执行和外界条件的变化而转换。在三态模型中进程状态分为三个基本状态即运行态就绪态阻塞态。在五态模型中进程分为新建态、终止态运行态就绪态阻塞态在七态模型中进程分为新建态、终止态运行态就绪态阻塞态就绪挂起态阻塞挂起态 但是在普遍的操作系统层面即站在操作系统学科的角度来说进程状态远远不止上面几种状态大致可能有运行、挂起、阻塞、新建、就绪、等待、挂机、死亡。其中最重要也是最难理解的几种状态分别是运行、阻塞、挂起。 下面我将从操作系统层面上的进程状态以及细化到Linux层面上的进程状态来综合讲解这三种状态 1.普遍的操作系统状态 下面我将针对运行、终止、堵塞、挂起这四个状态来进行讲解之后我们就能对这幅图有个清晰的认知。 1、进程运行 如果我们申请CPU资源暂时无法得到满足因为资源永远是少数的CPU只有一个你在申请这块资源可是其它进程可能也在申请这块资源如果给了A那么B和C该怎么办呢所以我们在申请的时候是需要排队的我们把此队列称为运行队列。因此我们申请其它慢设备资源也是需要排队的。 因为内存的容量有限而需要运行的程序非常多操作系统为了更好分配CPU和各种硬件资源并且更好地调度进程。操作系统为了合理分配CPU以及各种硬件资源也为了更好的调度各个进程会为CPU创建一个进程队列为每一个硬件都创建一个等待队列而让某一个进程处于运行状态本质上就是将该进程对应的PCB放入CPU的运行队列中然后再将PCB中维护进程状态的变量修改为相应的值比如0。因为进程PCB里面有进程的各种属性以及进程对应的代码和数据的地址所以CPU从运行队列中取出PCB后可以根据该PCB来得到进程的各种数据和指令然后执行相应运算。 总结所以进程处于运行状态并不一定意味着该进程此刻正在被运行只要该进程处于CPU的运行队列中即可。(注CPU是纳秒级的芯片运算速度非常快所以只要进程处于CPU的运行队列中我们就可以认为该进程正在被运行) 2、进程终止 这个进程还在只不过永远不运行了随时等待被释放进程都终止了为什么不立马释放对应的资源而要维护一个终止状态因为即使进程终止了但是你操作系统并不能立马就来释放这个进程就好比如你在一家餐厅的某个位置吃饭当你吃饭走人后这个位置能再次被别人使用吗当然不能因为服务员还没来得及收拾你的残渣。所以既然你已经终止了那么就需要一直维持着终止状态以此告诉操作系统等你不忙了赶紧来把我释放掉这就是随时等待被释放。 3、进程阻塞 和CPU一样我们计算机中的各种硬件也是十分有限的但是需要使用这些硬件资源的进程却有很多比如很多进程都需要向磁盘中写入数据又或者要通过网卡发送数据但是一个磁盘或者一个网卡在同一个时刻只能为一个进程提供服务那么如果此时有其他运行中的进程需要使用该硬件资源操作系统就会将该进程的PCB放入硬件的等待队列中等待硬件来为我提供服务。 上面这种由于访问某种硬件需要进行等待的状态就被称为阻塞状态阻塞状态本质上就是将进程的PCB从CPU的运行队列中剥离出来放入硬件的等待队列中然后将PCB中维护进程状态的变量修改为相应的值比如1待该进程获得对应的对应的硬件资源以后再将该进程放入CPU的运行队列中。 总结 并不是只有等待硬件资源进程才会处于阻塞状态一个进程等待另一个进程就绪、一个进程等待某种软件资源就绪等都会处于阻塞状态。 当进程访问某些资源磁盘、网卡……时如果该资源暂时没有准备好或者正在给其它进程提供服务这时当前进程要从runqueue移除并且将当前进程放入对应设备的描述结构体中的等待队列。而这件工作是由操作系统完成的。 当我们的进程在等待外部资源的时候该进程的代码就不会被执行此时我们作为用户看到的现象就是我的进程卡住了类似于你下载大型软件看视频会卡一样我们把这样的状态就称之为进程堵塞。 通俗说就是进程等待某种资源非CPU资源没有就绪的时候进程需要在该资源的等待队列中进行排队此时进程的代码并没有运行进程所处的状态就叫堵塞。 4、进程挂起 上面我们学习了阻塞状态处于阻塞状态的进程由于需要等待某种资源所以它对应的代码和数据在短期内并不会被执行此时它们仍存在在内存中就相当于浪费了内存资源而如果当前操作系统处于高IO的情况下内存空间不足操作系统就会选择将这些处于阻塞状态的进程对应的代码和数据拷贝一份存放到磁盘中然后释放内存中那一份从而节省出内存空间。 上面这种由于内存空间不足操作系统将在等待资源的进程对应的代码数据放到磁盘中以节省内存空间的状态就被称为挂起状态挂起状态不会移动进程的PCB只会移动进程对应的代码和数据。 总结如上当把该进程的代码和数据置换到磁盘中后释放掉这块空间此时内存就多出来了这块空间的容量可以短期内让其它进程使用因此操作系统通过这样的方式可以短暂的让进程只残留PCB剩下的代码和数据全部置换到磁盘上swap分区此时这样的进程就叫做进程挂起注意挂起进程并不是释放进程因为该进程对应的PCB仍然处于某硬件的等待队列中当该进程获得对应的资源以后操作系统仍然可以将该进程对应的代码和数据从磁盘加载到内存中来继续运行其本质是对内存数据的唤入唤出同时阻塞不一定挂起挂起也不一定阻塞也可能是新建挂起、就绪挂起甚至是运行挂起。 2.Linux操作系统状态 上面我们谈到的都是理论上的操作系统中进程的状态下面我们来学习具体Linux操作系统中进程的状态。 Linux内核源代码中对进程状态的定义如下 /*
- The task state array is a strange bitmap of
- reasons to sleep. Thus running is zero, and
- you can test for combinations of others with
- simple bit tests.
*/
static const char * const task_state_array[] {R (running), /* 0 /S (sleeping), / 1 /D (disk sleep), / 2 /T (stopped), / 4 /t (tracing stop), / 8 /X (dead), / 16 /Z (zombie), / 32 */
};可以看到Linux中进程一共有七种状态分别是运行、睡眠、深度睡眠 (磁盘休眠)、暂停、追踪暂停、死亡、僵尸。 1、运行状态 ® 一个进程处于运行状态running并不意味着进程一定在运行中它表明进程要么是在运行中要么在运行队列里。 示例 当我们编译运行此程序后进入死循环此程序没有访问其它外设资源读文件、读磁盘……此进程一直在cpu的队列里下面来查看此进程的状态 综上只要你的代码不访问外设只访问cpu资源只要能跑起来那么就是R状态。 2、(浅度)睡眠状态 (S) 示例 我们运行此代码并查看此进程的状态 我明明已经运行了此进程可为什么显示的会是S睡眠状态呢 这里执行了printf语句想要打印信息这就需要访问外设显示器但是想占用显示器的不止你一个其它进程可能正在使用操作系统就会把你的进程PCB放到显示器的等待队列里面当轮到你访问的时候操作系统再把你唤醒此时你就可以打印了这就是S睡眠状态对应的就是上文操作系统层面上的阻塞状态。总结外设的速度是要远远低于CPU的所以我们可以发现虽然 process 也在执行加法运算但是我们每次查询时进程基本都处于阻塞状态因为进程99%的时间都在等待硬件资源就绪只有1%的时间在进行加法运算以及执行打印代码。 S睡眠状态又叫做浅度睡眠和可中断睡眠。 浅度睡眠当进程处于S状态它可以随时被操作系统唤醒。可中断睡眠当进程处于S状态它可以被你随时kill杀掉。 3、深度睡眠状态 (D) D状态也是一种阻塞状态它也是要让进程去等待某种资源资源不就绪那么此进程就处于某种等待状态。一般而言Linux中如果我们等待的是磁盘资源我们进程阻塞所处的状态就是D。 下面对D状态进行深度剖析 假设我内存上一个500MB大小的进程要写到磁盘上我们假设磁盘写入这500MB的数据耗费时间很长实际非常快此时该进程只能处在内存里默默等待磁盘完工此时的进程就是S状态不会被运行等待磁盘资源就绪可是在进程等待的过程中内存中的进程越来越多操作系统也越来越忙假设操作系统在扫描所有进程的时候路过此S状态的进程见此进程啥事不干于是把它kill杀掉一般服务器压力过大OS是会终止用户进程的可是当磁盘写完数据回来无论写入成功与否呼叫此进程的时候发现进程竟然不见了。 我们假设上述磁盘读取的500MB数据很重要可是无论磁盘读取成功与否此数据都失效了因为对应的进程被OS杀掉了那么这个锅到底谁来背呢 对于操作系统OS本身的权限就是管理好系统如果内存不够挂起进程也无济于事为了防止操作系统崩溃OS有权利去自主的杀掉任何进程尤其是处于等待队列的进程。对于被kill的进程此进程就是把数据给磁盘进程也确实需要等待磁盘反馈结果可是等待的过程中莫名其妙被OS杀掉了所以与进程也无关。对于磁盘磁盘在这里扮演的角色就是一个跑腿的进程需要把数据写到磁盘上那磁盘听从指令慢慢写入这就需要进程在内存等待磁盘的反馈结果结果数据写入失败最后发现进程无响应磁盘也需要写入其他数据既然无响应磁盘就把数据丢弃了。 综上OS、进程、磁盘这三者好像都没有错误为了防止这种情况的发生Linux设计出了深度睡眠 (D) 状态处于深度睡眠状态的进程既不能被用户杀掉也不能被操作系统杀掉只能通过断电或者等待进程自己醒来也就是不可被中断睡眠。此时进程在等待磁盘的过程中就由浅度睡眠S演化为深度睡眠D具有了不可被中断属性自然就不会被OS误杀了。而要彻底解决掉D状态唯有关机重启和拔电源能够解决。 4、追踪暂停状态 (T/t) 在Linux中我们可以通过发送 SIGSTOP 信号给进程来停止T进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。 我们可以通过如下命令去查看 SIGSTOP 信号 kill -l暂停的意思是你本来是运行的后来让你暂停了假设现在有一个正在运行且不断循环的进程我们对此进程发送SIGSTOP也就是第19个信号该进程就进入到了暂停状态。 kill -19 pid我们再对该进程发送SIGCONT也就是第18个信号该进程就继续运行。 kill -18 pid我们将 process 暂停或者 continue 之后进程状态前面的 号消失了其实进程状态后面的 号代表着一个进程是前台进程没有 号就代表是后台进程对于前台进程我们可以使用【Ctrl c】将其终止也可以用 kill 命令杀死它但是对于后台进程来说我们只能通过 kill 命令来杀死它。 假设现在对我的一串代码进行调试并打了一个断点仔细观察我进程的状态 小t也是暂停不过它代表的是进程被调试的时候遇到断定所处的状态追踪状态。补充 5、死亡状态 (X) 这个状态只是一个返回状态当一个进程的退出信息被读取后该进程所申请的资源就会立即被释放该进程也就不存在了你不会在任务列表里看到这个状态。 6、僵尸状态 (Z) 假设程序员张三在外出跑步时看到前面原先跑的程序员李四好好的突然倒下了此时张三叫来了医生和警察首先医生检查了一下判断李四已经“嘠了”此时医生的任务已经完成并回去了接着警察派出法医去检测李四的死因当法医检测好死因后此时警察的事也完成了往后就是查案在走之前通知了李四的家属告知其具体情况并让他们来认领“李四”从李四的倒下一直到被抬走整个过程李四已无生命迹象但是并没有立刻抬走因为警察要确定死因在警察所排查的过程中李四所处的状态就是僵尸状态。 总结当一个进程将要退出的时候在系统层面该进程曾经申请的资源并不是立即被释放直接进入X死亡状态而是要暂时存储一段时间以供操作系统或是其父进程进行读取如果退出信息一直未被读取则相关数据是不会被释放掉的一个进程若是正在等待其退出信息被读取那么我们称该进程处于僵尸状态zombie。僵尸状态就是进程在退出时等待父进程或者操作系统来读取退出状态代码然后释放PCB的一种状态。 为什么进程要进入Z状态呢 1、进程被创建出来一定是因为有任务让这个进程执行当进程退出的时候不能立即释放该进程对应的资源需要保存一段时间一般需要把进程的执行结果告知给父进程或OS以此让我们得知任务的完成结果。 2、进程进入Z状态就是为了维护退出信息可以让父进程或os读取的。最后才能进入X状态。 四、两种特殊的进程
1.僵尸进程 什么是僵尸进程 回顾一下前面说到一个进程若是正在等待其退出信息被读取那么我们称该进程处于僵尸状态。而处于僵尸状态的进程我们就称之为僵尸进程。再来回顾下 僵死状态Zombies是一个比较特殊的状态。当进程退出并且父进程使用wait()系统调用,后面讲没有读取到子进程退出的返回代码时就会产生僵死(尸)进程僵尸进程会以终止状态保持在进程表中并且会一直在等待父进程读取退出状态代码。所以只要子进程退出父进程还在运行但父进程没有读取子进程状态子进程进入Z状态。 示例创建一个5s的僵尸进程 #includestdio.h
#includestdlib.h
#includeunistd.h
int main() {pid_t id fork();if (id 0){//child int cnt 5;while (cnt){printf(我是子进程我还剩下%d S\n, cnt–);sleep(1);}printf(我是子进程我已经僵尸了等待被检测\n);exit(0);}else{//father while (1){sleep(1);}}return 0; }运行该代码后我们可以通过以下监控脚本每隔一秒对该进程的信息进行检测 while :; do ps ajx | head -1 ps ajx | grep process | grep -v grep; sleep 1; echo —————————————————————————————————————————————————————————————————; done通过对上述pid和ppid的观察我们得知8862是父进程8861是子进程此时运行了5秒钟8862退出了状态变成了Z状态。并且子进程后面还提示了 defunct (失效的不再使用的)。 僵尸进程的危害 进程的退出状态必须被维持下去因为他要告诉关心它的进程父进程你交给我的任务我办的怎么样了。可父进程如果一直不读取那子进程就一直处于Z状态维护退出状态本身就是要用数据维护也属于进程基本信息所以保存在task_struct(PCB)中换句话说 Z状态一直不退出 PCB一直都要维护是的那一个父进程创建了很多子进程就是不回收是不是就会造成内存资源的浪费是的因为数据结构对象本身就要占用内存想想C中定义一个结构体变量对象是要在内存的某个位置进行开辟空间最终会导致内存泄漏 2.孤儿进程 我们针对上面的代码进行修改 #include stdio.h #include unistd.h #include stdlib.h #include sys/types.hint main() {int id fork();if(id 0){while(1){printf(我是父进程pid: %d, ppid: %d\n, getpid(), getppid());sleep(1);}}else if(id 0){while(1){printf(我是子进程pid: %d, ppid: %d\n, getpid(), getppid());sleep(1);}}else {perror(fork fail);exit(-1);}return 0; } 我们运行此程序并查看其进程的相关信息 图中我们可以看出子进程是7968父进程是7967当父进程7067退出的时候父进程为什么没有变成僵尸状态Z呢 因为父进程的父进程是bashbash会自动回收它的子进程也就是这里的父进程换言之这里没有看到僵尸是因为父进程被它的父进程bash回收了。 先前我们说过子进程退出的时候父进程要通过某种方式回收子进程但是这里很明显父进程先走了子进程还没退出可如果我子进程退出了那谁来回收我呢 总结这里操作系统就扮演了干爹的角色也就是如果父进程提前退出子进程就会被1号进程就是操作系统领养我们把这种被领养的进程称为孤儿进程。 补充 这里注意当父进程退出后由S变成S带加号的是前台进程不带加号的是后台进程并且这里使用ctrlc并不能结束进程需要手动kill进程 五、进程优先级 1.基本概念 1、什么是优先级 vs 权限是什么 优先级是进程获取资源的先后顺序比如你去医院看病但是看病的人很多这就需要排队挂号假设你在队尾虽然是队尾但是你也能打到饭只不过是先后的问题。权限是能和不能的问题好比如你听QQ音乐周董的歌只有vip用户才能看普通用户不能看因为你没有这个权限。 2、为什么会存在优先级 就好比如我去医院挂号这就是最典型的排队而排队的本质叫做确认优先级而排队的原因在于资源有限你挂号来晚了就没你的号了系统里面永远是进程占大多数而资源是少数cpu只有一个可是进程有n个这就导致竞争资源是常态所以一定要确认前后因此必须存在优先级来确定谁先谁后。 总结 cpu资源分配的先后顺序就是指进程的优先权priority。优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用可以改善系统性能。还可以把进程运行到指定的CPU上这样一来把不重要的进程安排到某个CPU可以大大改善系统整体性能。 2.查看系统进程 在linux或者unix系统中我们运行一个无限循环的process文件并用ps –l命令则会类似输出以下几个内容 ps -al我们很容易注意到其中的几个重要信息如下 UID : 代表执行者的身份PID : 代表这个进程的代号PPID 代表这个进程是由哪个进程发展衍生而来的亦即父进程的代号PRI 代表这个进程可被执行的优先级其值越小越早被执行NI 代表这个进程的nice值 3.PRI and NI Linux下用PRIpriority和NInice来确认优先级 PRI也还是比较好理解的即进程的优先级或者通俗点说就是程序被CPU执行的先后顺序此值越小进程的优先级别越高越大代表进程优先级越低。Linux下默认进程的优先级是80那NI呢?就是我们所要说的nice值了其表示进程可被执行的优先级的修正数值只能通过修改ni值来更改优先级PRI值越小越快被执行那么加入nice值后将会使得PRI变为 PRI(new)PRI(old)nice注意每次设置优先级这个old优先级都会被恢复成80。这样当nice值为负值的时候那么该程序将会优先级值将变小即其优先级会变高则其越快被执行所以调整进程优先级在Linux下就是调整进程nice值nice其取值范围是-20至19所以pri的取值范围是60至99。表示我们能调整40个级别 4.查看进程优先级信息 当我们创建一个进程后我们可以使用ps -al命令查看该进程优先级的信息。 ps -al5.通过top命令修改进程优先级ni 修改进程优先级就是在修改ni值这里有两种方法 1、通过top命令更改进程的nice值2、通过renice命令更改进程的nice值注意优先级不能随便修改它会打破调度器平衡的如果你非得修改就要用超级用户修改。 这里我们只讨论第一种方法 通过top命令更改进程的nice值 输入sudo top命令 top命令就相当于Windows操作系统中的任务管理器它能够动态实时的显示系统当中进程的资源占用情况。 按下‘ r ’键此时会要求你输入待调整nice值的进程的PID。 输入后按下回车此时会要求你输入调整后的nice值。 使用【q】命令退出。修改号后再ps -la查看是否已经修改 根据先前的性质不难得知ni的值设置为-10而PRI PRI(old)nice 80 - 10 70。假设我后续把ni的值设置为10最后ni的值为10PRI的值为80 10 90因为每次设置优先级这个old优先级都会被恢复成80所以是从80开始。 六、进程的其他概念 竞争性系统进程数目众多而CPU资源只有少量甚至1个所以进程之间是具有竞争属性的。为了高效完成任务更合理竞争相关资源便具有了优先级独立性多进程运行需要独享各种资源多进程运行期间互不干扰并行多个进程在多个CPU下分别同时进行运行这称之为并行并发多个进程在一个CPU下采用进程切换的方式在一段时间之内让多个进程都得以推进称之为并发 下面具体解释并发 多个进程在你的系统中运行 ! 多个进程在你的系统中同时运行进程不是占用了cpu就会一直执行到结束然后释放cpu资源我们遇到的大部分操作系统都是分时的所谓的分时就是操作系统会给每一个进程在以此调度周期中赋予一个时间片的概念。 如图假设进程1进入cpu运行假设操作系统给它分配10ms的时间如果10ms到了无论结果如何都不会再让你进程1继续运行了操作系统会把你进程1从cpu上剥离下来然后再调度进程2……假设往后每个进程都是分配10ms1s 1000ms那么在1s内这5个进程平均每个都要调度20次。 总结在一个时间段内多个进程都会通过切换交叉的方式让多个进程代码在一段时间内都得到推进这种现象我们叫并发。 补充1抢占式内核 我们的操作系统内部支持抢占式内核正在运行的低优先级进程但如果来个优先级更高的进程我们的调度器会直接把进程从cpu上玻璃放上优先级更高的进程这就是进程抢占。 补充2进程的 优先级 | 队列 操作系统内是允许不同的优先级的存在的且相同优先级的进程是可以存在多个的。但是进程是一个先进先出的队列如果在原有稳定的进程基础上突然来了一个优先级更高的进程那它就会随便插队吗这不就不符合队列的性质了。这里就可以借用指针数组、hash来解决 总结linux内核是根据不同的优先级将特定的进程放入不同的队列中而cpu就很自然的从数组的优先级最高的地方开始寻找进程。 七、进程切换 进程间是如何进行切换的。 CPU内部存在各种各样的寄存器可以临时的保存数据。而寄存器又分可见寄存器和不可见寄存器。当进程在被执行的时候一定会存在大量的临时数据会暂存在CPU内的寄存器中。当你要把下一个进程放上来的时候除了要把上一个进程拿走还要把你的历史数据拿走CPU同一时刻只能运行一个进程但是CPU的运算速度非常快所以位于CPU运行队列中的每一个进程都只运行一个时间片每个进程运行完一个时间片后被都被放到运行队列尾部等待下次运行这样使得在一个时间段中多个进程都能被运行。示例假如小王刚上大一还没开学随即填报了大学生征兵入伍为了保留学籍小王向学校申请了保留学籍此时学校要留存小王的数据个人信息学籍……。小王两年义务兵退伍后随即又向学校申请恢复学籍此时小王就可以从先前被切走的地方大一继续运行上学。此时学校扮演的角色就是cpu小王在学校产生的所有临时数据就是上下文数据小王就是一个进程小王当兵被招走就相等于被操作系统切换下去前提是在cpu内把临时数据保存好为了的是后续的恢复。 总结我们把进程在运行中产生的各种寄存器数据我们叫做进程的上下文 当进程被剥离需要保存上下文数据task_struct。当进程恢复的时候需要将曾经保存的上下文数据恢复到寄存器中。 参考文章进程概念和进程状态
- 上一篇: 建设造价信息网站做企业网站支付功能
- 下一篇: 建设执业资格注册管理中心网站网站建设总结报告
相关文章
-
建设造价信息网站做企业网站支付功能
建设造价信息网站做企业网站支付功能
- 技术栈
- 2026年04月20日
-
建设造价信息网站运城网站建设
建设造价信息网站运城网站建设
- 技术栈
- 2026年04月20日
-
建设悦生活网站中国正规现货交易平台
建设悦生活网站中国正规现货交易平台
- 技术栈
- 2026年04月20日
-
建设执业资格注册管理中心网站网站建设总结报告
建设执业资格注册管理中心网站网站建设总结报告
- 技术栈
- 2026年04月20日
-
建设执业资格注册管理中心网站页面设计怎么弄
建设执业资格注册管理中心网站页面设计怎么弄
- 技术栈
- 2026年04月20日
-
建设制作网站wordpress安装教程linux
建设制作网站wordpress安装教程linux
- 技术栈
- 2026年04月20日






