对进程的一些总结

进程

进程是对正在运行中的程序的一个抽象。进程是动态的概念。

比喻:做蛋糕的食谱就是程序、做蛋糕的人就是 CPU、而做蛋糕的各种原料都是输入数据进程就是科学家阅读食谱、取来各种原料以及烘焙蛋糕等一系例了动作的总和

进程内存空间布局

在这里插入图片描述

PCB

进程控制块PCB是进程存在的唯一标志,使得一个不能独立运行的程序成为一个能独立运行的进程
为什么说PCB是进程存在的唯一标志
证明:

  • 当进程被调度
    要从该进程的PCB中查出其现行状态及优先级;要根据其PCB中所保存的处理机状态信息,设置该进程恢复运行的现场,并根据其PCB中的程序和数据的内存始址,找到其程序和数据;

  • 进程在执行过程
    当需要和与之合作的进程实现同步,通信或者访问文件时,也都需要访问PCB;

  • 当进程暂停执行时
    也需要将其断点的处理机环境保存在PCB中。

可见在进程的整个生命期中,系统总是通过PCB对进程进行控制的,所以说PCB是进程存在的唯一标志

进程上下文切换

在这里插入图片描述
进程a切换为进程b的过程如下:
1.保存进程a的当前状态,包括程序计数器,寄存器,代码段,数据段等
2.更新PCB的信息,将a进程的状态有运行态修改为阻塞态,然后加入阻塞队列
3.更新b进程的PCB信息,从就绪转为运行状态,cpu运行b进程

进程的五种状态

五态:

  1. 创建状态:进程正在被创建时的状态,os为进程分配资源、初始化PCB;
  2. 就绪态,就绪态状态下进程是可运行的,但此时又有其他进程正在运行,所以当前进程不得不等待,此时的等待状态就是就绪状态。
  3. 运行态,进程正占用 CPU 时间片
  4. 阻塞态,除非某种外部事件发生,否则进程不能运行
  5. 结束状态:进程运行完毕,正在从系统中撤销的状态;os会回收进程拥有的资源
    在这里插入图片描述

进程状态的切换时机
在这里插入图片描述

举例理解:
现在我们写了如下一段代码,然后编译成可执行文件hello-name
在这里插入图片描述
在shell下执行./hello-name时,进程状态会发生如下变化:
在这里插入图片描述

挂起态

还有一个状态叫挂起状态

什么是挂起状态?
挂起态和阻塞态唯一的区别就是:阻塞态的进程在内存中,挂起态的进程不在硬盘中
由于虚拟内存的原因,进程使用的空间可能并没有映射到物理内存,而是在硬盘上,这时阻塞的进程就会出现挂起状态

即:进程不在内存中的等待状态即为挂起状态

挂起状态可以分为两种:

  • 阻塞挂起状态:进程在外存(硬盘)等待某个事件的出现则进入阻塞状态
  • 就绪挂起状态:进程在外存(硬盘),但只要进入内存,就进入就绪状态

这两种挂起状态加上前面的五种状态,就变成了七种状态变迁,见如下图:

在这里插入图片描述

详解进程状态

进程的创建

创建进程的过程如下:

  • 为新进程分配一个唯一的进程标识号,并申请一个空白的 PCB,PCB 是有限的,若申请失败则创建失败;
  • 为进程分配资源,此处如果资源不足,进程就会进入等待状态,以等待资源;
  • 初始化 PCB;
  • 如果进程的调度队列能够接纳新进程,那就将新进程插入到就绪队列,等待被调度运行;

哪些情况下会创建进程

  • 系统初始化(init)
  • 正在运行的程序执行了创建进程的系统调用(比如 fork)
  • 用户请求创建一个新进程
  • 初始化一个批处理工作

补充:
操作系统允许一个进程创建另一个进程,而且允许子进程继承父进程所拥有的资源,
当子进程被终止时,其在父进程处继承的资源会还给父进程。
同时,终止父进程时同时也会终止其所有的子进程。

fork系统调用

在UNIX系统中, 只有一个系统调用可以用来创建新进程:fork。
这个系统调用会创建一个与调用进程相同的副本。

当fork刚刚完成时,两个进程的内存、寄存器、程序计数器等状态都完全—致;但它们是完全独立的两个进程,拥有不同的PID与虚拟内存空间,在fork完成后它们会各自独立地执行,互不干扰。

子进程接着执行execve系统调用以修改其内存映射并运行一个新的程序。

int main(int argc, char *argv[])
7 {
8 printf("hello world (pid:%d)\n", (int) getpid());
9 int rc = fork();
10 if (rc < 0) { // fork failed; exit
11 fprintf(stderr, "fork failed\n");
12 exit(1);
13 } else if (rc == 0) { // child (new process)
14 printf("hello, I am child (pid:%d)\n", (int) getpid());
15 } else { // parent goes down this path (main)
16 printf("hello, I am parent of %d (pid:%d)\n",
17 rc, (int) getpid());
18 }
19 return 0;
20 }

运行这段程序(p1.c),将看到如下两种输出结果:

prompt> ./p1
hello world (pid:29146)
hello, I am parent of 29147 (pid:29146)
hello, I am child (pid:29147)
prompt>
prompt> ./p1
hello world (pid:29146)
hello, I am child (pid:29147)
hello, I am parent of 29147 (pid:29146)
prompt>

可以看到,hello world 只会输出一次,说明子进程不是从main开始执行。而是和父进程一样从fork返回处往下执行。

父子进程从fork()返回的值是不同的:
父进程获得的返回值是新创建子进程的PID
而子进程获得的返回值是0

然后两个进程被cpu调度的顺序也不一定。可能子进程先执行也可能父进程先执行。

进程的阻塞和就绪

进程的阻塞和唤醒(唤醒之后进入就绪态)是一对原语,必须成对使用

阻塞进程

当进程需要等待某一事件完成时,它可以调用阻塞语句把自己阻塞等待。而一旦被阻塞等待,处于阻塞状态的进程是绝对不可能自己叫醒自己的。它只能由另一个进程唤醒。

阻塞进程的过程如下:

  • 找到被阻塞进程的 PCB;
  • 如果该进程为运行状态,则保护其现场,将其状态转为阻塞状态,停止运行;
  • 将该 PCB 插入到阻塞队列中去;

唤醒进程
当该进程所期待的事件出现时,发现者进程用唤醒语句叫醒它。
过程如下:

  • 在该事件的阻塞队列中找到相应进程的 PCB;
  • 将其从阻塞队列中移出,并置其状态为就绪状态;
  • 把该 PCB 插入到就绪队列中,等待调度程序调度;

进程的终止

终止进程的过程如下:

  • 查找需要终止的进程的 PCB;
  • 如果处于执行状态,则立即终止该进程的执行,然后将 CPU 资源分配给其他进程;
  • 如果其还有子进程,则应将其所有子进程终止;
  • 将该进程所拥有的全部资源都归还给父进程或操作系统;
  • 将其从 PCB 所在队列中删除;

进程终止方式

  • 正常退出(exit,自愿的)
  • 错误退出(自愿的)
  • 系统错误(非自愿的)
  • 被其他进程杀死(kill,非自愿的)

工作进程 vs 守护进程

工作进程
它会完成这个程序需要完成的业务操作。如果用户线程全部结束了,意味着程序需要完成的业务操作已经结束了,系统可以退出了
守护进程
守护进程是一种特殊的进程,在后台默默地完成一些系统性的服务,比如垃圾回收线程、JIT线程都是守护线程。

僵尸进程 vs 孤儿进程

正常情况下:
当一个子进程完成它的工作并退出之后,它的父进程会取得该子进程的状态信息,使之正常消失。
但如果发生异常导致父进程没能正常工作,就会产生孤儿进程或僵尸进程

即:
父进程在子进程之前死了——孤儿进程
子进程死了但是父进程不收集其状态信息——僵尸进程

  • 僵尸进程
    任何一个子进程(init除外)在exit之后,并非马上就消失掉的,此时父进程没有来得及获取子进程的状态信息,子进程的进程描述符仍然保存在系统中。此时的子进程被称之为僵尸进程,等待父进程处理之后则会消失掉。(这是每个子进程在结束时都要经过的阶段)。
  • 孤儿进程
    如果父进程在子进程结束之前就退出了,则子进程成为孤儿进程,孤儿进程将由init进程接管。init将会以父进程的身份对该孤儿进程进行处理使之消失。

僵尸进程和孤儿进程的危害
如果大量的产生僵死进程或孤儿进程,子进程的状态信息得不到释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,最终将因为没有可用的进程号而导致系统不能产生新的进程

孤儿进程的解决办法:init进程代父进程收集子进程的状态信息

僵尸进程的解决办法:杀死父进程
僵死进程并不是问题的根源,罪魁祸首是产生出大量僵死进程的那个父进程。因此应该杀死这个父进程,让其不再产生子进程,同时init进程代父进程收集子进程的状态信息

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值