赞
踩
目录
特殊的进程:孤儿进程
并不意味着进程一定处在运行中,它表示进程处在运行中或者运行队列里
这和我们平时的理解有所不同,如果想知道其中缘由,需要我们深入理解cpu是如何运行进程的:
准备好运行的进程会链接在一起,形成一个运行队列。
OS会创建一个管理运行队列的结构体,结构体中含有指向进程头部和尾部的指针。
当cpu运行进程时,可以通过结构体的指向,直接获取队列头部的进程。
调度器:相当于一个函数,将运行队列作为参数传进来,就可以找到所有正在排列的所有进程。
**运行态:处于运行队列的进程就叫做处于运行状态。
在运行队列里的含义就是:我已经准备好了,可以随时被调用。
一个进程只要把自己放到CPU上开始运行了,是不是要一直到执行完毕,才把自己放下来?
不是!!!
如果我写一个while(1)死循环,那么在这个循环跑的时候,其他所有进程都不能运行,实际生活的经验告诉我们,这显然是不可能的。
为了防止一个进程在cpu上下不来,每一个进程都有一个叫做时间片的概念。比如 int t =10ms。当跑完时间片上的时间以后,进程就会从cpu上下来,放到队列的尾部。1s内可以跑很多个进程,所以用户看到每个进程都在跑。
在一段时间内,所有进程的代码都会被执行,叫做并发执行。
代码中存在大量的把进程从cpu上放上去和拿下来的动作,这个动作叫做进程切换。
表示进程等待某件事件完成,又叫做阻塞状态。这里的睡眠指可中断睡眠。
在学习c语言的过程中,我们都用过scanf函数,当提示我们从键盘输入数据但我们还未输入时,整个程序是不会往下继续进行的,此时这个进程就处于阻塞状态。
--------------------------------------------------------------------------------------------------------------------------------
在操作系统中绝大多数进程都处于阻塞状态,操作系统内存不足时,会想办法节省出来一些内存资源。
因为在阻塞状态时,进程的数据和二进制代码是用不到的,所以操作系统就将一部分进程的二进制代码放入磁盘中存储,仅仅留下PCB排队。这个过程叫做唤出。
当需要用到数据和二进制代码时,再将其加载进内存。这个过程叫做唤入。
也叫作不可中断睡眠态(深度睡眠),在这个状态的进程通常会等待IO状态的结束
都已经有了睡眠状态,为什么还有增加一个不可中断睡眠态?
上述三者只是各司其职,但却造成了数据的缺失,这时设计上的缺陷,所以引入了D状态。
D状态相当于有了一个免死金牌,即使是操作系统也不能杀掉这种状态下的进程。
僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。
僵尸进程会以终止状态保持在进程表中,并且一直等待父进程读取状态退出代码。
所以,只要子进程退出,父进程还在运行,但是父进程没有读取子进程状态,子进程进入Z状态
类似当一个人去世以后,必须要等到他的亲属得到通知以后,才能进行下一步的处理。
在进程中,子进程挂掉以后,要将执行结果等一些信息告诉父进程,父进程知道以后,才能被清理。
代码:
- #include<stdio.h>
- #include<sys/types.h>
- #include<unistd.h>
-
- int main()
- {
- printf("我是一个进程啦,my id is:%d,my parent id:%d\n",getpid(),getppid());
- sleep(2);
-
- pid_t id =fork();
- if(id == 0){
- int cur=5;
-
- while(cur){
- cur--;
- 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{
-
- }
-
- return 0;
- }
运行结果:
如果父进程一直不读取子进程的退出状态,那么子进程就一直处于Z状态?是的!
维护退出状态本质就是用数据维护,也属于进程的基本信息,存储在task_struct(PCB)中,换句话说,如果Z状态一直不退出,那么PCB一直都要维护?是的!
如果一个父进程有很多个子进程,就是不回收,是不是会造成内存的浪费?是的!
也就是说造成了内存泄漏?是的!
在后续的学习这中会更新避免出现僵尸进程的方法。
可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行
这个状态只是一个返回状态,你不会在任务列表里看到这个状态。
目前为止,出现的值得关注的进程状态已经全部讲完,下面我们来认识另外一种特殊的进程
孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
代码:
- #include<stdio.h>
- #include<sys/types.h>
- #include<unistd.h>
-
- int main()
- {
- printf("我是一个进程啦,my id is:%d,my parent id:%d\n",getpid(),getppid());
- sleep(2);
-
-
- pid_t id =fork();
- if(id ==0 ){
- while(1){
- printf("我是子进程,pid:%d,ppid:%d\n",getpid(),getppid());
- sleep(1);
- }
- }
- else if(id>0){
- int cur=5;
- while(cur){
- cur--;
- printf("我是父进程,pid:%d,ppid:%d\n",getpid(),getppid());
- sleep(1);
- }
- }
- else{
-
- }
-
- return 0;
- }
执行结果:
注:S+中的+表示在前台运行的意思,在前台运行的可以通过ctrl+c停止,在后台运行的不行,要通过信号,kill -9 PID
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。