edu网站开发,周口建设路网站,整站seo服务,深圳住建官网提示#xff1a;文章写完后#xff0c;目录可以自动生成#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、直接谈论Linux的进程状态 看看Linux内核源代码怎么说 1.1、R状态 ----- 进程运行的状态 1.2、S状态 ----- 休眠状态(进程在等待“资源”就绪) 1.3、T状… 提示文章写完后目录可以自动生成如何生成可参考右边的帮助文档 目录 前言 一、直接谈论Linux的进程状态 看看Linux内核源代码怎么说 1.1、R状态 ----- 进程运行的状态 1.2、S状态 ----- 休眠状态(进程在等待“资源”就绪) 1.3、T状态 ----- 暂停状态 1.4、t状态 ------ 当前的进程因为被追踪而暂停了 1.5、D状态 1.6、僵尸状态(Z) 1.7、死亡状态(X) 二、僵尸进程 下面我们创建一个进程来看一看 僵尸进程危害 三、孤儿进程 下面我们创建一个进程来看一看 四、运行状态 五、阻塞状态 六、挂起状态 七、进程切换的话题 总结 前言
世上有两种耀眼的光芒一种是正在升起的太阳一种是正在努力学习编程的你!一个爱学编程的人。各位看官我衷心的希望这篇博客能对你们有所帮助同时也希望各位看官能对我的文章给与点评希望我们能够携手共同促进进步在编程的道路上越走越远 提示以下是本篇文章正文内容下面案例可供参考
一、直接谈论Linux的进程状态 看看Linux内核源代码怎么说 为了弄明白正在运行的进程是什么意思我们需要知道进程的不同状态。一个进程可以有几个状态在 Linux内核里进程有时候也叫做任务。下面的状态在kernel源代码里定义 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 */
}; 操作系统要更改一个进程的状态它的原理其实就是更改 task_struct{}内部的状态属性(status)。 1.1、R状态 ----- 进程运行的状态
vim Makefile
testStatus:testStatus.cgcc -o $ $^ -g
.PHONY:clean
clean:rm -f testStatus这儿有一个替换方式
:%s/myprocess/testStatus/
//将 myprocess替换成 testStatus的可执行程序
vim testStatus.c
#include stdio.h
#include sys/types.h
#include unistd.hint main()
{while(1){printf(i am a process,pid:%d\n,getpid());}return 0;
}我们还可以用shell命令来一直刷新观察
while :; do ps ajx | head -1 ps ajx | grep testStatus | grep -v grep; sleep 1; done它其实一直处于一种休眠状态。
我们将打印的代码注释掉再来看一下程序
vim testStatus.c
#include stdio.h
#include sys/types.h
#include unistd.hint main()
{while(1){//printf(i am a process,pid:%d\n,getpid());}return 0;
}此时的代码就是一个非常纯粹的循环代码没有打印。
重新 make 编译一下 那么为什么我们加上 printf 的代码就看到了大量的 S(休眠状态)呢
printf的本质是往显示器上打印而程序的运行是在千里之外的云服务器上跑根据冯诺依曼体系结构显示器是一个外设所以CPU在跑当前的程序时把数据写入到我们当前的内存当中打印数据的顺序先写入到内存里再刷新到外设里。可是我们无法保证每次打印的时候显示器的状态都是就绪的因为程序是CPU跑的CPU的运算速度要比显示器本身的速度要快的多所以进程在被调度的时候要访问显示器的资源因为资源要一直在显示器上打所以大部分时间相比较CPU来讲大部分时间我们对应的进程都在等待我们的设备资源是否就绪。就比如代码执行到 printf 的时候CPU是几纳秒而数据刷新到显示器的时间是几毫秒其余大部分时间都在等待中而这等待的时间就是(S)休眠状态。
1.2、S状态 ----- 休眠状态(进程在等待“资源”就绪)
#include stdio.h
#include sys/types.h
#include unistd.hint main()
{while(1){sleep(10);//printf(i am a process,pid:%d\n,getpid());}return 0;
}可中断睡眠处于S睡眠状态依旧可以随时被外部信息打断比如ctrl c就醒来了。 进程在运行时 (取地址符)那么进程就默认在后端运行。 此时 R 后面就没有 了 代表进程是在前端运行的还是在后端运行的。 1.3、T状态 ----- 暂停状态 T/t 让进程暂停等待被进一步唤醒。 1.4、t状态 ------ 当前的进程因为被追踪而暂停了 1.5、D状态 DLinux系统比较特有的一种进程状态。当A进程需要大量的数据写入磁盘的时候等待磁盘写入数据此时A进程的状态就是休眠状态当磁盘写入数据完成或者写入失败的话都要向A进程汇报情况。但是有一个场景系统中内存严重不足时操作系统有一个特权Linux操作系统有权力杀掉进程来释放空间。那么此时你的A进程被操作系统杀掉了用来释放空间过来3、4秒之后磁盘已经写入了1GB的数据了还想要再次写入A进程的数据但是失败了失败之后要汇报情况可是A进程已经被操作系统杀掉了此时B进程也要向磁盘写入数据那么磁盘就去照顾B进程去了那么已经写入A进程的那1GB数据就丢失了(假如那1GB的数据是转账记录的话那事故是很严重的)那该怎么办呢为了避免这种情况就可以把等待磁盘数据写入后需要拿到磁盘返回结果的进程状态设为D状态。D不可被杀深度睡眠不可中断睡眠。 消除D状态有两种情况
1、让进程自己醒来
2、重启不行的话就得断电了。
1.6、僵尸状态(Z)
僵尸状态也叫僵死状态它是在进程在死亡状态之前的状态。当一个进程运行完毕、出现问题或者被杀掉以后它所占用的内存资源和退出状态没有被它的父进程回收此时这个进程的状态就称为僵尸状态。
1.7、死亡状态(X)
当一个进程执行结束或者是被操作系统杀掉它的PCB被操作系统删除并且对应加载到磁盘上的二进制代码也被删除此时这个进程就处于死亡状态了。
当一个进程占有内存的所有资源被回收以后这个进程就处于死亡状态。进程的死亡状态是看不到的因为只有在回收完成的那一刻才会出现PCB不存在也就搜索不到这个进程所以也无法演示。
二、僵尸进程 僵死状态Zombies是一个比较特殊的状态。当进程退出并且父进程使用wait()系统调用,后面讲 没有读取到子进程退出的返回代码时就会产生僵死(尸)进程。僵死进程会以终止状态保持在进程表中并且会一直在等待父进程读取退出状态代码。所以只要子进程退出父进程还在运行但父进程没有读取子进程状态子进程进入Z状态。 Linux中的进程退出的时候会将自己的退出信息保留在自己的PCB当中如果没有人读取PCB中进程退出的消息那么进程就会一直不释放一般会把进程的代码和数据结果释放掉但是PCB的数据结构不会释放直到将来对进程进行等待如果不等待那么进程会一直处于僵尸状态。如果把进程的退出信息读取了和等待了那么这个进程才会变成X状态从而将进程的所有资源全部释放。 一个进程退出的时候它不会立即退出而是会现处于一种僵尸状态如果父进程不会对我们这个进程进行回收或者等待的话那么对应的进程会一直处于僵尸状态。 下面我们创建一个进程来看一看
#include stdio.h
#include sys/types.h
#include unistd.hint main()
{pid_t id fork();if(id 0){// childint cnt 5;while(cnt){printf(I am child, cnt: %d, pid: %d\n, cnt, getpid());sleep(1);cnt--;}}else{// parentwhile(1){printf(I am parent, running always!, pid: %d\n, getpid());sleep(1);}}return 0;
} 子进程已经运行完毕但是需要维持自己的退出信息在自己的进程task_struct会记录自己的退出信息未来让父进程进行读取。
如果没有父进程读取僵尸进程会一直存在(内核数据结构task_struct会一直存在)进程的代码和数据会释放。
将来子进程被 waitpid(系统调用接口) 等待方式读取了那么这个子进程会由Z状态变为X状态之后由OS来释放。
僵尸进程危害 进程的退出状态必须被维持下去因为他要告诉关心它的进程父进程你交给我的任务我办的怎么样了。可父进程如果一直不读取那子进程就一直处于Z状态是的维护退出状态本身就是要用数据维护也属于进程基本信息所以保存在task_struct(PCB)中换句话说Z状态一直不退出PCB一直都要维护是的那一个父进程创建了很多子进程就是不回收是不是就会造成内存资源的浪费是的因为数据结构对象本身就要占用内存想想C中定义一个结构体变量对象是要在内存的某个位置进行开辟空间内存泄漏?是的如何避免后面讲。 三、孤儿进程 父进程如果提前退出那么子进程后退出进入Z之后那该如何处理呢父进程先退出子进程就称之为“孤儿进程”。孤儿进程被1号init进程领养当然要有init进程回收喽。 下面我们创建一个进程来看一看
#include stdio.h
#include sys/types.h
#include unistd.hint main()
{pid_t id fork();if(id 0){// childint cnt 5;while(cnt){printf(I am child, cnt: %d, pid: %d\n, cnt, getpid());sleep(1);//cnt--;}}else{// parentint cnt 5while(cnt){printf(I am parent, running always!, pid: %d\n, getpid());sleep(1);cnt--;}}return 0;
} 我们已经启动的所有的进程我们怎么从来没有关心过僵尸进程内存泄漏呢
直接在命令行中启动的进程它的父进程是bashbash会自动回收新进程的Z僵尸进程。
四、运行状态
操作系统为了合理分配CPU以及各种硬件资源保证各个进程的正常运行。操作系统会为CPU创建一个进程队列也为每一个硬件都创建一个等待队列。
而某一个进程处于运行状态本质上就是操作系统将该进程对应的PCB放入CPU的运行队列中然后再将PCB中维护进程状态的变量修改为相应的值。
PCB里面有进程的各种属性值以及对应的代码的地址。所以CPU从运行队列中找到PCB取出数据后可以根据数据得到进程的各种属性值和指令然后执行相应代码。进程处于运行状态并不意味着该进程此时一定正在被运行只要该进程处于CPU的运行队列中即可。
注意CPU是处理数据的速度在纳秒级运算速度非常快所以只要进程处于CPU的运行队列中我们就可以认为该进程正在被运行。 一个进程一旦持有CPU会一直运行到这个进程结束吗
不会。CPU基于时间片进行轮转调度的。(Linux不是这样调度的这只是OS教材调度方法之一)
让多个进程以切换的方式进行调度在一个时间段内同时得以推进代码就叫做并发。
每一个CPU都要有一个自己的运行队列有两个CPU的话会存在真正意义上的有两个调度队列。任何时刻都同时有多个进程在真的同时运行我们叫做并行。
五、阻塞状态
CPU处理数据的速度极快是我们计算机中的各种硬件处理数据的万倍比如一个磁盘或者一个网卡同时只能为一个进程服务但是在计算机中需要使用这些硬件资源(磁盘等)的进程会有很多。
如果在硬件为一个进程服务时有其他运行中的进程也需要使用该硬件资源操作系统就会将该进程的PCB放入硬件的等待队列中进程会等待硬件来为自己提供服务。
不是只有CPU才有运行队列各种硬件设备也有自己的等待队列。
由于多个进程需要访问某种硬件进程PCB在硬件等待队列中等待硬件服务自己的状态就被称为阻塞状态。阻塞状态在本质上就是将进程的PCB从CPU的运行队列中放入硬件的等待队列中然后将PCB中维护进程状态的变量也会修改为相应的值。当该进程获得对应的硬件资源服务时再将该进程放回CPU的运行队列中。
注意并不是只有等待硬件资源的进程才处于阻塞状态一个进程等待另一个进程就绪、一个进程等待软件资源就绪等也是阻塞状态。
六、挂起状态 上面我们学习了阻塞状态处于阻塞状态的进程由于需要等待某种资源所以它对应的代码和数据在短期内不会被处理这里的短期指的是对于操作系统而言。但它们的数据仍储存在内存中占用存储空间但是不执行相当于浪费了内存资源。而如果当前操作系统处于高IO大量向内存输入和向外部设备输出数据的情况下可用的内存空间不足操作系统就会选择性的将这些处于阻塞状态的进程对应的代码和数据转移到磁盘中从而节省出内存空间。
这种由于内存空间不足操作系统将在等待资源的进程对应的代码和数据放到磁盘中以节省内存空间的状态就被称为挂起状态。挂起状态不会移动进程的PCB只会移动进程对应的代码和数据。
挂起并不是释放进程因为对应的PCB仍然在硬件的等待队列中当该进程获得对应的资源服务以后操作系统仍然可以将该进程对应的代码和数据从磁盘加载到内存中来继续运行其本质是对内存数据的唤入唤出。
七、进程切换的话题 A进程在CPU运行队列中运行的时间片到了之后A进程会脱离CPU的运行进程B进程会进入CPU的运行队列中运行那么比如A进程在CPU中已经运行到了第50行代码后时间片到了退出CPU当A进程再次进入CPU的时候是从新开始运行呢还是接上上回第50行的代码继续运行呢
CPU里面有一套寄存器会保留A进程运行的数据当A进程退出CPU的时候A进程在CPU中已经运行的数据将由 task_struct 这个结构体来保存当A进程再次进入CPU时数据还会回到寄存器原来的位置所以A进程会接着第50行继续运行。
进程的切换最重要的一件事情是上下文数据的保护和恢复。
CPU内的寄存器
寄存器本身是硬件具有数据的存储能力CPU的寄存器硬件只有一套CPU内部的数据可以有多套有几个进程就有几套和该进程对应的上下文数据。
寄存器 寄存器的内容 总结
好了本篇博客到这里就结束了如果有更好的观点请及时留言我会认真观看并学习。不积硅步无以至千里不积小流无以成江海。