【操作系统二】进程与线程

一、进程的概念

打开windows系统下的任务管理器,可以看到进程的相关信息,有我们正在使用的应用进程,还有很多后台进程,这些后台进程是系统运行必要的服务进程。而我们未使用的应用程序是不会出现在任务管理器中的,由此也可以发现进程是动态的,是处于执行过程中(处于执行过程中并不是指一定获取到了cpu执行权)的程序。以上是对进程的一些感性理解。

程序:静态的代码,就是存放在磁盘中的可执行文件,就是一系列指令的集合。(不论是语言的代码,最终都会编译成机器码并由计算机硬件执行)

进程:动态的代码执行过程,是程序的一次执行过程。不仅仅包括程序的执行代码,还包括执行过程中,在内存中产生的一系列用于操作系统控制的数据结构。比如PCB(进程控制块)。同一个程序多次执行会对应多个进程。操作系统为了管理这些进程,会为每个进程分配一个进程ID,用于区分。

二、进程的组成

进程是运行的程序,那么程序运行过程中会由哪些部分组成呢?运行时需要什么资源,又会在内存中生成什么样的数据结构,来保证进程的正确运作呢?

答:操作系统为进程分配一个唯一的、不重复的ID,PID(进程控制块)、操作系统还需要保存该进程所属的用户ID、记录为该进程分配了多少资源(比如内存、IO设备、文件)、记录进程的运行情况(cpu使用时间、磁盘使用情况、网络使用情况)。这些信息都被保存在一个叫做PCB(程序控制块)的数据结构中,操作系统对各个并发的进程进行管理时(资源管理、进程上cpu的控制和调度),所需要的所有信息全都保存在PCB中。

进程是一个动态的运行时的概念,那它的边界是什么?什么时候进程开始,又是在什么时候结束?

答:PCB是进程的唯一标识,进程被创建时会随之创建PCB,当进程结束时,会回收PCB。因此开始的标志就是PCB创建、结束的标志是PCB回收。

进程由哪些内容组成?

答:进程由三部分组成,PCB、程序部分、数据部分。PCB是给操作系统使用的,程序部分和数据部分是给进程自己用的。

PCB包括进程描述信息(PID、UID)、进程控制和管理信息(cpu使用时间、磁盘使用时间、目前状态运行态/阻塞态/挂起态/终止态)、资源分配清单、cpu相关信息(用于操作系统控制进程切换从而实现并发)。

程序部分是进程运行的代码(实际上是编译后的底层指令序列)。

数据部分是进程推进过程中产生的各种中间数据。

三、进程的特征

进程调度是指操作系统决定让哪一个进程上CPU运行。进程是操作系统分配资源的最小单位,线程是操作系统调度的最小单位。

动态性:进程是程序的一次执行过程,是一个动态的执行过程。包括PCB、程序部分、数据部分。

并发性:内存中有多个进程,各个进程由操作系统调度而并发执行。

独立性:进程独立获取资源、独立运行的基本单位。

异步性:多个进程并发执行,各个进程本身以不可预知的速度向前推进。异步性导致的未知会使得系统出现潜在的错乱危险,因此操作系统必须提供“进程同步机制”来解决异步问题,保证在需要时让各个进程按照确定的顺序依次执行,保证可控。

四、进程控制

进程的唯一标识是PCB,那么系统中由如此多的PCB,如何组织这些PCB呢?

答:有两种方式:链接和索引表。不管是链接还是索引表,基本都会分为三部分,当前执行进程的PCB、处于就绪态的PCB链表(索引表)、处于阻塞态的PCB链表(索引表)。

什么是进程控制?

答:进程有五种状态,创建态、就绪态、运行态、阻塞态、终止态。进程控制就是实现进程在这几个状态之间的转换。

如何实现进程控制?

答:进程控制通过原语实现。原语是操作系统内核提供的指令,原语执行具有“原子性”,一气呵成地执行。之所以要通过原语实现状态转换的一气呵成,是因为状态转换有多个步骤才能完成(比如将PCB状态修改,将PCB块从阻塞队列移动到就绪队列),如果不是一气呵成地执行,当执行到中间步骤时被中断,那么会出现数据不一致,出现错错乱。

原语的原子性时如何实现的呢?

答:正常情况下,cpu每次执行完成一条指令都会检查是否有中断信号需要处理,如果有则暂停当前运行进程,转而执行相应的中断处理程序。而多条指令无法连续执行的原因就在可能出现中断上。只要屏蔽了中断,那么指令就能连续执行了。而原语的原子性就是通过两个特权指令实现的,关中断指令和开中断指令。在原语的多条指令执行之前,先执行关中断指令,然后cpu不再进行中断检查,原语的多条指令一气呵成地完成,再执行开中断指令,恢复正常。这两条指令必须运行在核心态,如何运行在用户态,用户可以随意执行,那操作系统的管理功能就能被用户关闭了。

有哪些进程控制相关的原语?

进程的创建、进程的终止、进程的阻塞、进程的唤醒、进程的切换。无论哪个进程控制原语,要做的有三种事情:更新PCB中的信息(修改进程状态标志、保存/恢复运行环境即cpu寄存器的读写)、将PCB插入合适的队列(阻塞、就绪、执行等队列)、分配/回收资源。

五、进程通信

进程是资源分配的最小单位,各个进程独立分配内存空间,各个进程只能直接访问自己的内存空间,不可以直接访问其它进程的内存空间,但是各个进程又有交换信息的必要性,操作系统提供了进程之间通信的机制,主要有三种方式:共享存储、消息传递、管道通信。(想一想JVM的内存模型,其各个线程的之间的通信机制就有点像共享存储的方式,各个线程的工作内存通过主内存交换信息)

1、共享存储

共享存储的方式下,划出一块内存区域来作为共享空间,两个进程对共享空间的访问时互斥的,而互斥的工具由操作系统提供(比如PV操作)

2、消息传递

进程之间的交换信息通过格式化的信息来交换,可以由发送进程直接挂到接收进程的缓冲队列中,或者通过中间的信箱暂存交换。

3、管道通信

管道通信其实和共享存储有点像,管道通信也是开辟一块内存区域作为管道,各个进程互斥访问管道,当管道写满时write写调用会被阻塞,当为空时read读调用会被阻塞,如果没写满不能读,如果没读空不能写。一旦数据被读出,管道中的该数据就被清理。可以看出管道是半双工通信,通过两个管道可以实现全双工。

六、线程的概念和特点

如果没有线程的概念,对于qq这个应用如果既要开视频,又要发文字,还要下文件,如果实现?

答:只能采用多个进程的方式,开视频由一个进程实现,发文字由一个进程实现,下文件由一个进程实现。这种方式存在的问题是,这些进程需要频繁地进行切换,而进程的切换的代价很高(保存寄存器状态到PCB、更新快表等等),因此这种实现方式代价很高。而引入线程后,可以实现一个进程内的各个线程之间的切换来实现不同的功能,而各个线程的切换代价又相对小一些。引入线程后,进程不再是cpu调度的基本单位,而线程成为cpu调度的基本单位,此时视频聊天、文字发送、文件下载可以通过多个线程分别实现。

为什么引入线程?

答:很多进程都需要并发的执行很多事,而传统的进程只能串行地执行一系列的指令,只能通过多个进程来实现逻辑,而多个进程之间切换代价又很高。为此,引入了线程,来增加并发度,从而实现一个进程内也可以并发地处理各种任务。

进程是资源分配的基本单位(比如内存、IO设备等都是分配给进程,线程是cpu调度的基本单位),进程切换时需要保存、恢复进程运行环境,还需要切换内存地址空间,而由于线程共享进程内的资源,因此同一进程内的各个线程切换时不需要像进程切换那样复杂(不同进程的线程之间切换代价依然很大)。因此引入线程后,不仅进程之间可以并发,线程之间也可以并发,系统的并发度提升了。

进程之间的内存区域独立,因此通信时必须由操作系统提供的特权指令来实现,必须从用户态转换到核心态,开销大。而同一进程内的线程共享该进程的内存空间,进行通信时无需操作系统干预,开销小。

七、线程的实现方式

操作系统是如何实现线程的呢?

答:有三种实现方式,用户级线程、内核级线程、组合方式

很多编程语言提供了强大的线程库,用户级线程的实现方式中,线程的管理工作由用户程序负责,线程的切换不需要cpu变态,操作系统感受不到线程的存在。早期的unix系统采用这种方式。

内核级线程,windows、linux等系统均采用这种方式。线程的管理工作由操作系统完成,线程的切换需要cpu变态,操作系统能够感受到内核线程的存在。

Java虚拟机就是采用这种方式,将多个用户线程映射到多个内核线程上,这样是对前两种方式的平衡,即提高了并发度(一个内核线程阻塞其它内核线程还可以执行);又避免了用户线程和内核线程一对一时线程切换的高代价。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值