进程的描述
进程的定义
进程:一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程。
进程的组成
进程由程序的代码、处理的数据、下一条指令、一组通用的寄存器、堆栈、一组资源
进程和程序的联系
程序是产生进程的基础
程序的每次运行构成不同的进程
进程是程序的功能体现
通过多次执行,一个程序可以对应多个进程;通过调用关系,一个进程可以包括多个程序。
进程和程序的区别
~进程是动态的,程序是静态的;程序是有序代码的集合;进程是程序的执行,进程有核心态和用户态。
为什么有和核心态? 读写文件的时候,进程给操作系统请求,有系统做读写操作,这个时候是核心态。
~进程是暂时的,程序是永久的;进程是一个状态变化的过程,程序可以长久保存。
~进程跟程序的组成不同:进程:程序、数据和进程控制块(进程状态信息)
例子06:26 类比一
进程的特点
1、动态性:动态创建、结束。
2、并发性:一段时间内有多个进程在进行(调度)。 并行:同一个时刻执行多个进程
3、独立性:不同进程的工作不互相影响。页表是保证进程独立性的重要工具。
4、制约性:因访问共享数据、资源或进程间同步产生的制约。
例子 04:21
程序 = 算法 + 数据结构描述进程的数据结构:进程控制块(过程控制块,PCB)。操作系统为每个进程都维护了一个PCB,用来保存与该进程有关的各种状态信息。
进程控制结构
进程控制结构进程控制块:操作系统管理控制进程运行所用的信息集合。操作系统用PCB来描述进程的基本情况以及运行变化的过程,PCB是进程存在的唯一标志。
使用进程控制块
进程的创建:为该进程生成一个PCB;
进程的终止:回收它的PCB;
进程的组织管理:通过对PCB的组织管理来实现;
PCB有什么信息?
(一)进程标识信息。如本进程的标识,本进程的产生者标识(父进程标识);用户标识。
(二)处理机状态信息保存区。保存进程的运行现场信息:
用户可见寄存器,用户程序可以使用的数据,地址等寄存器。
控制和状态寄存器,如程序计数器(PC),程序状态字(PSW)。
栈指针,过程调用/系统调用/中断处理和返回时需要用到它。
(三)进程控制信息:
调度和状态信息,用于操作系统调度进程并占用处理机使用。
进程间通信信息,为支持进程间的与通信相关的各种标识、信号、信件等,这些信息存在接收方的进程控制块中。父子进程的关系信息。
存储管理信息,包含有指向本进程映像存储空间的数据结构。
进程所用资源,说明由进程打开、使用的系统资源,如打开的文件等。
有关数据结构连接信息,进程可以连接到一个进程队列中,或连接到相关的其他进程的PCB。
PCB的组织方式:
链表:(方便插入和删除)同一状态的进程其PCB成一链表,多个状态对应多个不同的链表各状态的进程形成不同的链表:就绪链表、阻塞链表
索引表:(如果进程数量一定)同一状态的进程归入一个索引表(由索引指向PCB),多个状态对应多个不同的索引表各状态的进行形成不同的索引表:就绪索引表、阻塞索引表
进程的状态
进程的生命期管理
进程创建
引起进程创建的3个主要事件:
系统初始化时;
用户请求创建一个新进程;
正在运行的进程执行了创建进程的系统调用;
进程运行
内核选择一个就绪的进程,让它占用处理机并执行。为何选择?如何选择?调度算法。
进程等待
比如:当从硬盘读数据的时候, 需要比较长的时间,这个时候可以让进程等待。cpu去做其他事情。
进程唤醒
进程结束
进程状态变化模型
进程的三种基本状态:进程在生命结束前处于且仅处于三种基本状态之一不同系统设置的进程状态数目不同。
运行状态(Running):当一个进程正在处理机上运行时。
就绪状态(Ready):一个进程获得了除处理机(cpu)之外的一切所需资源一旦得到处理机即可运行.
等待状态(又称阻塞状态Blocked):一个进程正在等待某一事件而暂停运行时。如等待某资源,等待输入/输出完成。
Running->Ready (时间片轮询)
可能的状态变化
NULL→New:一个新进程被产生出来执行一个程序。
New-Ready: 当进程被创建完成并初始化后,一切就绪准备运行时,变为就绪状态。是否会持续很久?
Ready-Running:处于就绪状态的进程被进程调度程序选中后,就分配到处理机上来运行。
Running→Exit:当进程表示它已经完成或者因出错,当前运行进程会由操作系统作结束处理。
Running→Ready:处于运行状态的进程在其运行过程中,由于分配给它的处理机时间片用完而让出处理机。谁完成?
Runing→Blocked:当进程请求某样东西且必须等待时。例如:等待定时器,读写文件。
Blocked-Ready:当进程要等待某事件到来时,它从阻塞状态变到就绪状态。
进程挂起模型
挂起状态:
阻塞挂起状态:进程在外存并等待某事件的出现
就绪挂起状态:进程在外存,但只要进入内存,就可以运行
与挂起相关的状态转换,
挂起(Suspend) :把一个进程从内存转到外存;
阻塞到阻塞挂起:没有进程处于就绪状态或就绪进程要求更多内存资源时,会进行这种转换,以提交新进程或运行就绪进程;
就绪到就绪挂起:当有高优先级阻塞(系统认为会很快就绪的)进程和低优先就绪进程时,系统会选择挂起低优先级就绪进程;
运行到就绪挂起:对抢先式分时系统,当有高优先级阻塞挂起进程因事件出现而进入就绪挂起时,系统可能会把运行进程转到就绪挂起状态;
**在外存时的状态转换:**阻塞挂起到就绪挂起:当有阻塞挂起进程因相关事件出现时,系统会把阻塞挂起进程转换为就绪挂起进程。
解挂/激活(Activate) :把一个进程从外存转到内存;
**就绪挂起到就绪:**没有就绪进程或挂起就绪进程优先级高于就绪进程时,会进行这种转换;
阻塞挂起到阻塞:当一个进程释放足够内存时,系统会把一个高优先级阻塞挂起(系统认为会很快出现所等待的事件)进程转换为阻塞进程;
状态队列
由操作系统来维护一组队列,用来表示系统当中所有进程的当前状态;
不同的状态分别用不同的队列来表示(就绪队列、各种类型的阻塞队列);
每个进程的PCB都根据它的状态加入到相应的队列当中,当一个进程的状态发生变化时,它的PCB从一个状态队列中脱离出来,加入到另外一个队列。
线程
为什么要有线程?
【案例】编写一个MP3播放软件。核心功能模块有三个:(1)从MP3音频文件当中读取数据;(2)对数据进行解压缩;(3)把解压缩后的音频数据播放出来。
问题:播放出来的声音能否连贯?各个函数之间不是并发执行,影响资源的使用效率; read 很慢,会影响效率。
问题:进程之间如何通信,共享数据?另外,维护进程的系统开销较大:创建进程时,分配资源、建立PCB;撤消进程时,回收资源、撤消PCB;进程切换时,保存当前进程的状态信息。
怎么来解决这些问题?
满足以下特性:(1)实体之间可以并发地执行;(2)实体之间共享相同的地址空间:
线程是什么?
从两个方面来重新理解进程从资源组合的角度:
进程把一组相关的资源组合起来,构成了一个资源平台(环境),包括地址空间(代码段、数据段)、打开的文件等各种资源:
从运行的角度:代码在这个资源平台上的一条执行流程(线程)。
线程很容易实现进程内的资源共享。
线程=进程一共享资源
线程的优点:
一个进程中可以同时存在多个线程;
各个线程之间可以并发地执行;
各个线程之间可以共享地址空间和文件等资源。
线程的缺点:
一个线程崩溃,会导致其所属进程的所有线程崩溃。
如何选择进程和线程?
高性能计算的时候,天气预报、空气动力学、水利。性能要求高,控制流程相对单一,用线程。
互联网中,打开一个网页,安全性要求较高,不能影响其他网页,用进程合适
线程所需的资源
线程和进程的比较
进程是资源分配单位,线程是CPU调度单位;
进程拥有一个完整的资源平台,而线程只独享必不可少的资源。如寄存器和栈;
线程同样具有就绪、阻塞和执行三种基本状态,同样具有状态之间的转换关系;
线程能减少并发执行的时间和空间开销:
线程的创建时间比进程短;因为可以利用进程的状态信息
线程的终止时间比进程短;
同一进程内的线程切换时间比进程短;属于同一个页面
由于同一进程的各线程间共享内存和文件资源,可直接进行不通过内核的通信;
线程的实现
主要有三种线程的实现方式:
用户线程:在用户空间实现(操作系统看不见,用户程序的库来管理);POSIX Pthreads, Mach c -thread, Solaris线程
内核线程:在内核中实现(操作系统能看到的);Windows, Solaris, Linux
轻量级进程:在内核中实现,支持用户线程Solaris(轻量级过程)
用户线程与内核线程的对应关系.
用户线程控制管理
在用户空间实现的线程机制,它不依赖于操作系统的内核,由一组用户级的线程库函数来完成线程的管理,包括进程的创建、终止、同步和调度等。
由于用户线程的维护由相应进程来完成(通过线程库函数),不需要操作系统内核了解用户线程的存在,可用于不支持线程技术的多进程操作系统;
每个进程都需要它自己私有的线程控制块(TCB)列表,用来跟踪记录它的各个线程的状态信息(PC、栈指针、寄存器),TCB由线程库函数来维护;
用户线程的切换也是由线程库函数来完成,无需用户态/核心态切换,所以速度特别快;
允许每个进程拥有自定义的线程调度算法。
用户线程的缺点:
1、阻塞性的系统调用如何实现?如果一个线程发起系统调用而阻塞,则整个进程在等待;
2、当一个线程开始运行后,除非它主动地交出CPU的使用权,否则它所在的进程当中的其他线程将无法运行;
3、由于时间片分配给进程,故与其它进程比,在多线程执行时,每个线程得到的时间片较少,执行会较慢。
内核线程(windows)
是指在操作系统的内核当中实现的一种线程机制,由操作系统的内核来完成线程的创建、终止和管理。PCB主要管理资源, 调度则由TCB完成。
在支持内核线程的操作系统中,由内核来维护进程和线程的上下文信息(PCB和TCB);
线程的创建、终止和切换都是通过系统调用/内核函数的方式来进行,由内核来完成,因此系统开销较大;(这也就是windows 比linux大的原因)
在一个进程当中,如果某个内核线程发起系统调用而被阻塞,并不会影响其他内核线程的运行;
时间片分配给线程,多线程的进程获得更多CPU时间;Windows NT和Windows 2000/XP支持内核线程。
轻量级进程
轻量化过程它是内核支持的用户线程。一个进程可有一个或多个轻量级进程,每个量级进程由一个单独的内核线程来支持。(Solaris多对一/Linux)
上下文切换
切换内容:寄存器(PC,SP,…,局部变量)
进程控制–加载和执行
Exec()调用允许一个进程“加载”一个不同的程序并且在main开始执行(事实上 _start)它允许一个进程指定参数的数量(argc)和它字符串参数数组(argv).
如果调用成功,它是相同的进程…但是它运行了一个不同的程序!!代码,stack(栈) & heap(堆)重写
fork()的简单实现:
对子进程分配内存
复制父进程的内存和CPU寄存器到子进程里
开销昂贵!!
在99%的情况里,我们在调用fork()之后调用exec()
在fork( )操作中内存复制是没有作用的
子进程将可能关闭打开的文件和连接
开销因此是高的
为什么不能结合它们在一个调用中(OS/2, Windows)?
vfork ()
一个创建进程的系统调用,不需要创建一个同样的内存映像
一些时候称为轻量级fork()
子进程应该几乎立即调用exec()
copy on write :先把子进程页表项指向父进程,只有写操作的时候把父进程的页面复制成两份, 只有读操作的时候,不需要复制,避免不必要的复制。
进程控制–等待和终止进程
wait()系统调用是被父进程用来等待子进程的结束一个子进程向父进程返回一个值,所以父进程必须接受这个值并处理
wait()系统调用担任这个要求
它使父进程去睡眠来等待子进程的结果
当一个子进程调用exit()的时候,操作系统解锁父进程,并且将通过exit()传递得到的返回值作为wait调用的一个结果(连同子进程的pid一起)
如果这里没有子进程存活,wait()立刻返回
当然,如果这里有为父进程的僵尸等待,wait ()立即返回其中一个值(并且解除僵尸状态)
wait()就是等待子进程释放自身可以释放的资源并退出的信号,然后父进程就可以去释放子进程的PCB。进程不能释放自身的PCB
进程结束执行之后,它调用exit()
这个系统调用:
将这程序的“结果”作为一个参数关闭所有打开的文件,连接等等释放内存释放大部分支持进程的操作系统结构检查是否父进程是存活着的:如果是的话,它保留结果的值直到父进程需要它;在这种情况里,死亡,但是它进入了僵尸(zombie/defunct)状态如果没有,它释放所有的数据结构,这个进程死亡清理所有等待的僵尸进程进程终止是最终的垃圾收集(资源回收)
如果父进程先于子进程死亡,怎么办?
root process 会定期扫描是否存在僵尸进程,有的话就可以清理僵尸进程。
执行 exec()会在哪个状态? 答:可能在run ready blokced 状态,因为
总结
进程管理资源,线程管理执行流程。