操作系统(4)

进程同步

协作进程是可以与在系统内执行的其他进程互相影响的进程。互相协作的进程可以直接共享逻辑空间(即代码和数据),或者通过文件或消息来共享数据。
假设一个系统有n个进程,每个进程有一个代码段称为临界区(critical section),在该区中进程可能改变共同变量、更新一个表、写一个文件等。这种系统的重要特征是当一个进程进入临界区,没有其他进程可以允许在临界区执行。临界区问题是设计一个以便进程协作的协议。
临界区问题的解答需要以下三步:

  • 互斥(mutual exclusion),如果有进程在临界区执行,那么其他进程都不能在临界区执行。
  • 前进(progress):如果没有进程在其临界区执行且有进程需进入临界区,那么只有那些不在剩余区内执行的进程可以参与选择,以确定谁能进入临界区,且这种选择不能无限推迟。
  • 有限等待(bounded waiting):从一个进程进入临界区的请求,直到该请求允许为止,其他进程允许进入其临界区的次数有上限。

一般来说,任何临界问题只需要一个简单工具——锁来防护临界区,就可以避免竞态条件。

原子事务

临界区的互斥确保临界区原子性执行,即如果两个临界区并发执行,那么其结果相当于它们按某个顺序执行。但是有些情况下,希望临界区作为一个逻辑工作单元,比如资金转账,一个账号要借,另一个账号要贷,为了保持数据一致性,要么同时借同时贷,要么不借也不贷。(两者不分先后,不能出现一个操作成功另个操作失败的情况)
数据库系统关注于数据的存储和提取及数据的一致性。执行单个逻辑功能的一组指令成为事务(transaction)。处理事务的主要问题是不管出现什么计算机系统的可能失败,都要保证事务的原子性。已成功完成执行的终止事务称为提交(committed)。否则称为撤销(aborted)。
被终止的事务必须对其修改的数据不产生任何影响,以确保原子特性(同一个整体)。被终止的事务所访问的数据恢复到事务开始执行前,这个操作称为回退(rolled back)。确保这一属性是系统的责任。

基于日志的恢复

确保原子性的一种方法是在稳定存储上记录有关事务对其访问的数据做各种修改的描述性信息,具有如下域:

  • 事务名称:执行写事务的唯一名称
  • 数据项名称: 所写数据项的唯一名称
  • 旧值:写操作前的数据项的值
  • 新值:写操作后的数据项的值

在日志写进稳定存储之前,不能允许真正更新数据项。

检查点

当系统出现错误,必须参考日志以确定哪些事务需要重做而哪些事务需要撤销,需要搜索整个日志。这种方法有两个缺点:

  • 搜索过程费时
  • 大多数所根据的算法需要重做的事务已经跟新了数据,恢复需要比较长的时间

为了降低额外开销,引入了检测点(checkpoint)的概念,在执行时系统维护日志,另外系统定时执行检查点并执行以下动作:

  • 将当前驻留在易失性存储(比如内存)上的日志输出到稳定存储上。
  • 将当前驻留在易失性存储上的所有修改数据输出到稳定存储上。
  • 在稳定存储上输出一个日志记录< checkpoint>

这样就能通过检查点减少额外开销。

并发原子操作

当多个原子操作并发执行的时候, 其实相当于这些事务按任意顺序串行执行,称为串行化(serializability)。可以简单地在临界区内执行每个事务,即所有这些事务共享一个信号量mutex,其初始值为1。当事务开始执行的时候,其第一个动作是执行wait(mutex),当事务提交之后执行signal(mutex)
考虑一个系统,其中有两个数据项A和B,它们被两个事务T0和T1读和写。假设按照T0和T1的顺序原子地执行,这个执行顺序称为一个调度。对于n个事务,共有n!个不同有效的调度。
如果允许两个事务重叠执行,就需要定义冲突操作(conflicting operation)。假设T0和T1读写的是不同数据字段,那么无论如何并行都不会产生错误,如果一个调度S可以通过一系列非冲突操作而转换成串行调度S`,就说明S为冲突可串行化的(conflict serializable)。
确保串行化能力的一种方法是为每个数据项关联一个锁,要求每个事务遵循加锁协议(locking protocol)以控制锁的获取和释放。对数据项加锁有许多方式,这里只讨论两种:

  • 共享(shared):如果事务Ti获得了数据项Q的共享模式锁(记为S),那么Ti可以读取这一项,但不能修改它。
  • 排他(exclusive):如果事务Ti获得了数据项Q的排他模式锁(记为X),那么Ti可以读写数据Q。

为了访问数据Q,事务Ti必须首先按适当模式锁住Q。

死锁

在多道程序环境下,多个进程可能竞争同一个资源。如果申请的资源被其他进程占有,等待的进程无法改变其状态,这种情况称为死锁(deadlock)。
如果有以下4个条件同时满足,就会造成死锁:

  • 互斥。至少有一个资源属于非共享模式。
  • 占有并等待:一个进程必须至少占有一个资源,并等待另一个资源,而该资源为其他进程所占有。
  • 非抢占:资源不能被抢占,即资源只能在进程完成任务后自动释放。
  • 循环等待:有一组等待线程,P0的资源为P1占有,P1的资源为P2占有,….Pn的资源为P0占有。

死锁可以有以下处理方法:

  • 可以使用协议预防或避免死锁,确保系统不进入死锁状态。
  • 可允许系统进入死锁状态,然后检测它,并加以修复。
  • 可忽视这个问题,认为死锁不会发生。

第三种方法为绝大多数操作系统采用,因此开发人员要自己处理死锁。
要解决这个问题,先来看一下产生死锁的4个必要条件,肯定无法通过第一个条件解决,因为有一部分资源是非共享的。如果想通过第二个条件解决,必须保证一个进程申请一个资源的时候,不能占有其他资源。如果想通过第三个条件解决,可以使用如下协议:如果一个进程占有资源并申请一个不能立即分配的资源,那么其现已分配的资源可以被抢占,这个协议通常应用于状态可以保存和恢复的资源,如CPU寄存器和内存。死锁的第四个条件是循环等待,一个确保此条件不成立的方法是对所有资源进行完全排序,且要求每个进程按递增顺序来申请资源。

这篇主要介绍了进程同步相关,下篇会详细介绍内存管理操作系统(5)

猜你喜欢

转载自blog.csdn.net/sysuzhyupeng/article/details/78453103
今日推荐