操作系统——进程

个人博客地址:https://alexaccele.github.io/

操作系统——进程

进程的定义与特征

为了使参与并发执行的每个程序都能够独立地运行,在操作系统中配置了一个专门的数据结构,称为进程控制块(Process Control Block,PCB)。系统利用PCB来描述进程的基本情况和活动过程,进而控制和管理进程。通常称进程实体为进程。
创建进程,实质上是创建进程实体中的PCB;
撤销进程,实质上是撤销进程的PCB。

定义:

  1. 进程是程序的一次执行
  2. 进程是可以和别的计算并行执行
  3. 进程是程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位

特征:

  • 动态性:进程的实质是程序的一次执行过程,进程是动态产生,动态消亡的。
  • 并发性:任何进程都可以同其他进程一起并发执行。
  • 独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位。
  • 异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进。

进程的状态及转换

进程的几种状态:

  1. 新建状态(New):新创建了一个线程对象。
  2. 就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态
    的线程位于“可运行线程池”中,变得可运行,只等待获取CPU的使用权。即在就绪状态的
    进程除CPU之外,其它的运行所需资源都已全部获得。
  3. 运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
  4. 阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。
  5. 死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

直到线程进入就绪状态,才有机会转到运行状态。

阻塞的情况分三种:

  1. 等待阻塞:运行的线程执行wait()方法,该线程会释放占用的所有资源,JVM会把该线
    程放入“等待池”中。进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用
    notify()或notifyAll()方法才能被唤醒,
  2. 同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM
    会把该线程放入“锁池”中。
  3. 其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该
    线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕
    时,线程重新转入就绪状态。

线程变化的状态转换图如下:

进程控制块PCB

PCB作为进程实体的一部分,记录了操作系统所需的,用于描述进程的当前情况以及管理进程运行的全部信息,是操作系统中最重要的记录型数据结构。

PCB的作用是使一个在多道程序环境下不能独立运行的程序(含数据)成为一个能独立运行的基本单位,一个能与其他进程并发执行的进程。

  1. 作为独立运行基本单位的标志。
  2. 能实现间断性运行方式。
  3. 提供进程管理所需的信息。
  4. 提供进程调度所需要的信息。
  5. 实现与其他进程的同步与通信。

进程控制块中的信息

  1. 进程标识符:用于唯一地标识一个进程。
  2. 处理机状态:也称为处理机的上下文,主要是由处理机的各种寄存器中的内容组成的。包括通用寄存器、指令寄存器、程序状态字PSW、用户栈指针。
  3. 进程调度信息:(1)进程状态,指明进程的当前状态;(2)进程优先级,用于描述进程使用处理机的优先级别的一个整数;(3)进程调度所需的其他信息,比如进程已等待CPU的时间总和、进程已执行的时间总和等;(4)事件,是指进程由执行状态转变为阻塞状态所等待发生的事件,即阻塞原因。
  4. 进程控制信息:用于进程控制所必须的信息,(1)程序和数据的地址;(2)进程同步和通信机制;(3)资源清单,在该清单中列出了进程在运行期间所需的全部资源(除CPU外的),还有一张已分配到该进程的资源清单;(4)链接指针,本进程所在队列的下一个进程的PCB的首地址。

进程控制块的组织方式

线性方式:将系统中所有的PCB都组织在一张线性表中,将该表的首地址存放在内存的一个专用区域中。

链接方式:把具有相同状态进程的PCB分别通过PCB中的链接字链接成一个队列

索引方式:系统根据所有进程状态的不同,建立几张索引表。

进程的创建

引起创建进程的事件

导致一个进程去创建另一个进程的典型事件有四类:

  1. 用户登录:在分时系统中,用户在终端键入登录命令后,若成功登录,系统将为该用户建立一个进程,并把它插入到就绪队列中。
  2. 作业调度:在多道批处理系统中,当作业调度程序按一定的算法调度到某些作业时,便将其装入内存,创建进程,并插入到就绪队列中。
  3. 提供服务:当运行中的用户程序提出某种请求后,系统将专门创建一个进程来提供用户所需要的服务。
  4. 应用请求:由用户进程自己创建新进程,以便使新进程以同创建者进程并发运行的方式完成特定任务。

进程的创建

  1. 申请空白PCB,为新进程申请获得唯一的数字标识符,并从PCB集合中索取一个空白PCB.

  2. 为新进程分配其运行所需的资源。包括各种物理和逻辑资源,如内存、文件、I/O设备和CPU时间等。这些资源或从操作系统或仅从其父进程获得。新进程对这些资源的需求详情一般也要提前告知操作系统或其父进程。 例如, 为新进程的程序和数据以及用户栈分配必要的内存空间时,操作系统必须知道新进程所需内存的大小: 1 对于批处理作业,其大小可在用户提出创建进程要求时提供;2 若是为应用进程创建子进程,也应是在该进程提出创建进程的请求中给出所需内存的大小;3 对于交互型作业,用户可以不给出内存要求而由系统分配一定的空间;如果新进程要共享某个已在内存的地址空间(即已装入内存的共享段),则必须建立相应的链接。

  3. 初始化进程控制块(PCB)。PCB的初始化包括: 1 初始化标识信息,将系统分配的标识符和父进程标识符填入新 PCB中;2 初始化处理机状态信息,使程序计数器指向程序的入口地址,使栈指针指向栈顶; 3 初始化处理机控制信息,将进程的状态设置为就绪状态或静止就绪状态,对于优先级,通常是将它设置为最低优先级,除非用户以显式方式提出高优先级要求。

  4. 如果进程就绪队列能够接纳新进程,便将新进程插入就绪队列。

进程的终止

引起进程终止的3种事件

  • 正常结束:表示进程的任务已经完成

  • 异常结束:是指进程在运行时发生了某种异常事件, 使程序无法继续运行。常见的异常事件有:

    1.越界错,这是指程序所访问的存储区,已越出该进程的区域;

    2.保护错,指进程试图去访问一个不允许访问的资源或文件, 或者以不适当的方式进行访问,例如,进程试图去写一个只读文件;

    3.非法指令,指程序试图去执行一条不存在的指令。出现该错误的原因可能是程序错误地转移到数据区,把数据当成了指令;

    4.特权指令错,指用户进程试图去执行一条只允许OS执行的指令;

    5.运行超时,指进程的执行时间超过了指定的最大值;

    6.等待超时,指进程等待某事件的时间超过了规定的最大值;

    7.算术运算错,指进程试图去执行一个被禁止的运算,例如,被0除;

    8.I/0故障,这是指在I/O过程中发生了错误等。

  • 外界干预:是指进程应外界的请求而终止运行。这些干预有:

    1.操作员或操作系统干预,指如果系统中发生了某事件,例如,发生了系统死锁, 由操作员或操作系统采取终止某些进程的方式使系统从死锁状态中解救出来;

    2.父进程请求,指当子进程已完成父进程所要求的任务时,父进程可以提出请求结束该子进程;

    3.因父进程终止,指当父进程终止时,它的所有子进程也都应当结束,因此,OS在终止父进程的同时,也将它的所有子孙进程终止。

进程的终止过程

  1. 根据被终止进程的标识符,从PCB集合中检索出该进程的PCB,从中读出该进程的状态;

  2. 若被终止进程正处于执行状态,应立即终止该进程的执行,并置调度标志为真,用于指示该进程被终止后应重新进行调度;

  3. 若该进程还有子孙进程,还应将其所有子孙进程也都予以终止, 以防它们成为不可控的进程;

  4. 将被终止进程所拥有的全部资源或者归还给其父进程,或者归还给系统;

  5. 将被终止进程(PCB)从所在队列(或链表)中移出,等待其它程序来搜集信息。

进程间的通信方式

  • 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关
    系的进程间使用。进程的亲缘关系通常是指父子进程关系。

  • 有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程
    间的通信。

  • 信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访
    问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,
    主要作为进程间以及同一进程内不同线程之间的同步手段。

  • 消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标
    识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限
    等缺点。

  • 信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。

  • 共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共
    享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其
    他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,
    来实现进程间的同步和通信。

  • 套接字( socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于
    不同及其间的进程通信。

进程与线程对比

  • 进程是资源分配的最小单位,线程是程序执行的最小单位。

  • 进程是系统进行资源分配和调度的一个独立单位.

  • 线程是进程的一个实体,是CPU调度和分派的基本单位

  • 进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。

  • 线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。

  • 但是多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。

优缺点

线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。
同时,线程适合于在SMP机器上运行,而进程则可以跨机器迁移。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,进程调度算法是操作系统中非常重要的一部分。常见的进程调度算法有先来先服务(FCFS)、短作业优先(SJF)、高响应比优先(HRRN)、时间片轮转(RR)等。下面是这些算法的 Python 实现: 1. 先来先服务(FCFS): ```python def FCFS(processes): waiting_time = 0 turn_around_time = 0 completion_time = 0 for process in processes: completion_time += process['burst_time'] turn_around_time += completion_time - process['arrival_time'] waiting_time += turn_around_time - process['burst_time'] return waiting_time / len(processes), turn_around_time / len(processes) ``` 2. 短作业优先(SJF): ```python def SJF(processes): processes = sorted(processes, key=lambda x: x['burst_time']) waiting_time = 0 turn_around_time = 0 completion_time = 0 for process in processes: completion_time += process['burst_time'] turn_around_time += completion_time - process['arrival_time'] waiting_time += turn_around_time - process['burst_time'] return waiting_time / len(processes), turn_around_time / len(processes) ``` 3. 高响应比优先(HRRN): ```python def HRRN(processes): waiting_time = 0 turn_around_time = 0 completion_time = 0 for i, process in enumerate(processes): if i == 0: completion_time = process['burst_time'] else: response_ratio_list = [] for j in range(i): response_ratio = (completion_time - processes[j]['arrival_time'] + processes[j]['burst_time']) / processes[j]['burst_time'] response_ratio_list.append(response_ratio) max_response_ratio_index = response_ratio_list.index(max(response_ratio_list)) selected_process = processes.pop(max_response_ratio_index) completion_time += selected_process['burst_time'] turn_around_time += completion_time - selected_process['arrival_time'] waiting_time += turn_around_time - selected_process['burst_time'] return waiting_time / len(processes), turn_around_time / len(processes) ``` 4. 时间片轮转(RR): ```python def RR(processes, time_slice): waiting_time = 0 turn_around_time = 0 completion_time = 0 while processes: for i in range(len(processes)): if processes[i]['burst_time'] > time_slice: completion_time += time_slice processes[i]['burst_time'] -= time_slice else: completion_time += processes[i]['burst_time'] turn_around_time += completion_time - processes[i]['arrival_time'] waiting_time += turn_around_time - processes[i]['burst_time'] processes.pop(i) break return waiting_time / len(processes), turn_around_time / len(processes) ``` 这里的 `processes` 是一个列表,其中每个元素是一个字典,表示一个进程的信息,如下所示: ```python processes = [ {'name': 'P1', 'arrival_time': 0, 'burst_time': 8}, {'name': 'P2', 'arrival_time': 1, 'burst_time': 4}, {'name': 'P3', 'arrival_time': 2, 'burst_time': 9}, ... ] ``` 在这个列表中,每个进程有一个名称、到达时间和执行时间。你可以根据自己的需要修改这些信息,来测试这些进程调度算法的实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值