第三章 进程同步 【期末复习|考研复习】
计算机操作系统系列文章传送门:
第一章 计算机系统概述
第二章 进程管理
第三章 进程同步
第四章 内存管理
第五章 文件管理
第六章 输出输出I/O管理
文章目录
- 第三章 进程同步 【期末复习|考研复习】
- 前言
- 三、进程同步
- 3.1 临界资源
- 3.1.1 互斥
- 3.1.2 同步
- 3.2 信号量
- 3.2.1 信号量机制实现进程互斥/同步
- 3.3 经典同步问题
- 3.3.1 单一生产者消费者
- 3.3.2 多生产者多消费者
- 3.3.3 读者写者问题
- 3.4管程
- 3.5 死锁
- 3.5.1 含义
- 3.5.2 死锁、饥饿、死循环的区别
- 3.5.3 死锁的必要条件
- 3.5.4 什么时候发生死锁
- 3.5.5 死锁的处理策略
- 死锁避免——银行家算法
- 死锁的检测与解除:
- 3.6 进程同步的方法
- 3.7 线程同步方法
- 3.8 Linux的进程管理
- 下一章 第四章 内存管理
前言
给大家整理了一下计算机操作系统中的重点概念,以供大家期末复习和考研复习的时候使用。
参考资料是王道的计算机操作系统和西电的计算机操作系统。
三、进程同步
3.1 临界资源
我们把一个时间段内只允许一个进程使用的资源称为临界资源。许多变量、数据、内存缓冲区等都属于临界资源。对临界资源的访问,必须互斥地进行。
3.1.1 互斥
互斥,亦称间接制约关系。进程互斥指当一个进程访问某临界资源时,另一个想要访问该临界资源的进程必须等待。当前访问临界资源的进程访问结束,释放该资源之后,另一个进程才能去访问临界资源。为了实现对临界资源的互斥访问,同时保证系统整体性能,需要遵循以下原则:1、空闲让进。临界区空闲时,可以允许一个请求进入临界区的进程立即进入临界区;2、忙则等待。当已有进程进入临界区时,其他试图进入临界区的进程必须等待;3、有限等待。对请求访问的进程,应保证能在有限时间内进入临界区(保证不会饥饿);4、让权等待。当进程不能进入临界区时,应立即释放处理机,防止进程忙等待。
3.1.2 同步
同步,亦称为直接制约关系,是指为完成某种任务而建立的两个或多个进程,这些进程因为某些位置上协调他们的工作次序而等待、传递信息所产生的制约关系。进程之间的直接制约关系源于他们之间的相互合作。
3.2 信号量
用户进程可以通过使用操作系统提供的一对原语来对信号量进行操作,从而很方便的实现了进程互斥、进程同步。**信号量其实就是一个变量(可以是一个整数,也可以是更复杂的记录型变量),**可以用一个信号量来表示系统中某种资源的数量,比如:系统中只有一台打印机,就可以设置一个初值为1的信号量。原语是一种特殊的程序段,其执行只能一气呵成,不可被中断。原语是由关中断/开中断指令实现的。一对原语: wait(S)原语和 signal(S)原语,可以把原语理解为我们自己写的函数,函数名分别为 wait和 signal,括号里的信号量s其实就是函数调用时传入的一个参数。简称PV操作。
3.2.1 信号量机制实现进程互斥/同步
实现互斥是信号量semaphore mutex =1(初始为1)(初始值为N的话表示最多由于N个线程可以访问)
实现同步是信号量 semaphore cond=0 (初始为0)
3.3 经典同步问题
3.3.1 单一生产者消费者
3.3.2 多生产者多消费者
若缓冲区为1则可以不用加互斥,如果缓冲区大于1则必须加互斥。
3.3.3 读者写者问题
1、读者优先
当有读者在时禁止写者进入,因此设置计数器count来表示当前访问buffer的读者数量
2、读写公平
3、哲学家进餐问题
4、吸烟者问题
3.4管程
信号量机制存在的问题 : 编写程序困难、易出错。
管程的构成:管程相当于对临界区资源进行抽象而编写的一个类。管程是一种特殊的软件模块,有这些部分组成:1、局部于管程的共享数据结构说明(一个类);2、对该数据结构进行操作的一组过程:(类中的方法);3、对局部于管程的共享数据设置初始值的语句(类中的变量);4、管程有一个名字(类名);
管程的特征:1、局部于管程的数据只能被局部于管程的过程所访问(类中变量有自己的作用范围);2、一个进程只有通过调用管程内的过程才能进入管程访问共享数据;这种互斥特性是由编译器来实现的;3、每次仅允许一个进程在管程内执行某个内部过程。
3.5 死锁
3.5.1 含义
在并发环境下,各进程因竞争资源而造成的一种互相等待对方手里的资源,导致各进程都阻塞,都无法向前推进的现象,就是“死锁“。发生死锁后若无外力干涉。这些进程都将无法向前推进。
3.5.2 死锁、饥饿、死循环的区别
死锁:各进程互相等待对方手里的资源,导致各进程都阻塞,无法向前推进的现象。
饥饿:由于长期得不到想要的资源,某进程无法向前推进的现象。比如:在短进程优先(SPF)算法中,若有源源不断的短进程到来,则长进程将一直得不到处理机,从而发生长进程“饥饿”。
死循环:某进程执行过程中一直跳不出某个循环的现象。有时是因为程序逻辑bug 导致的,有时是程序员故意设计的。
3.5.3 死锁的必要条件
1、互斥条件:只有对必须互斥使用的资源的争抢才会导致死锁(如哲学家的筷子、打印机设备)。像内存、扬声器这样可以同时让多个进程使用的资源是不会导致死锁的(因为进程不用阻塞等待这种资源)。2、不剥夺条件:进程所获得的资源在未使用完之前,不能由其他进程强行夺走,只能主动释放。3、请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又被其他进程占有,此时请求进程被阻塞,但又对自己已有的资源保持不放。4、循环等待条件:存在一种进程资源的循环等待链,链中的每一个进程已获得的资源同时被下一个进程所请求。
3.5.4 什么时候发生死锁
1、对系统资源的竞争。各进程对不可剥夺的资源(如打印机)的竞争可能引起死锁,对可剥夺的资源(CPU)的竞争是不会引起死锁的。2、进程推进顺序非法。请求和释放资源的顺序不当,也同样会导致死锁。例如,并发执行的进程P1、P2分别申请并占有了资源R1、R2,之后进程p1又紧接着申请资源R2,而进程p2又申请资源R1,两者会因为申请的资源被对方占有而阻塞,从而发生死锁。3、信号量的使用不当也会造成死锁。如生产者-消费者问题中,如果实现互斥的P操作在实现同步的P操作之前,就有可能导致死锁。(可以把互斥信号量、同步信号量也看做是一种抽象的系统资源)
3.5.5 死锁的处理策略
1、预防死锁。破坏死锁产生的四个必要条件中的一个或几个。2、避免死锁。用某种方法防止系统进入不安全状态,从而避免死锁(银行家算法)。3、死锁的检测和解除。允许死锁的发生,不过操作系统会负责检测出死锁的发生,然后采取某种措施解除死锁。
预防死锁:
死锁避免——银行家算法
数据结构:长度为m的一维数组 Available表示还有多少可用资源,n×m矩阵Max表示各进程对资源的最大需求数,n×m矩阵Allocation表示已经给各进程分配了多少资源,n×m矩阵Max - Allocation = Need矩阵表示各进程最多还需要多少资源。用长度为m的一位数组Request表示进程此次申请的各种资源数。
算法步骤:检查当前的剩余可用资源是否能满足某个进程的最大需求,如果可以,就把该进程加入安全序列,并把该进程持有的资源全部回收。不断重复上述过程,看最终是否能让所有进程都加入安全序列。
死锁的检测与解除:
1、死锁的检测:为了能对系统是否已发生了死锁进行检测,必须:①用某种数据结构来保存资源的请求和分配信息;②提供一种算法,利用上述信息来检测系统是否已进入死锁状态。
如果按上述过程分析,资源分配图最终能消除所有边,就称这个图是可完全简化的。此时一定没有发生死锁(相当于能找到一个安全序列)。如果最终不能消除所有边,那么此时就是发生了死锁。
2、死锁的解除:资源剥夺法。挂起(暂时放到外存上)某些死锁进程,并抢占它的资源,将这些资源分配给其他的死锁进程。但是应防止被挂起的进程长时间得不到资源而饥饿。撤销进程法(或称终止进程法)。强制撤销部分、甚至全部死锁进程,并剥夺这些进程的资源。这种方式的优点是实现简单,但所付出的代价可能会很大。因为有些进程可能已经运行了很长时间,已经接近结束了,一旦被终止可谓功亏一篑,以后还得从头再来。3、进程回退法。让一个或多个死锁进程回退到足以避免死锁的地步。这就要求系统要记录进程的历史信息,设置还原点。
3.6 进程同步的方法
1.使用fork系统调用创建进程:使用fork系统调用无参数,fork会返回两次,分别返回子进程id和0,返回子进程id的是父进程,返回0的是子进程。(fork系统调用是用于创建进程的;fork创建的进程初始化状态与父进程一样;系统会为fork的进程分配新的资源)
2.共享内存:在某种程度上,多进程是共同使用物理内存的,但是由于操作系统的进程管理,进程间的内存空间是独立的,因此进程默认是不能访问进程空间之外的内存空间的。(共享存储允许不相关的进程访问同一片物理内存;共享内存是两个进程之间共享和传递数据最快的方式;共享内存未提供同步机制,需要借助其他机制管理访问;)
3.Unix域套接字,域套接字是一种高级的进程间通信的方法,可以用于同一机器进程间通信。套接字(socket):为网络通信中使用的术语。Unix系统提供的域套接字提供了网络套接字类似的功能,如Nfinx、uWSGI等。服务端和客户端分别使用Unix域套接字的过程:
3.7 线程同步方法
1、互斥锁:互斥锁是最简单的线程同步的方法,也称为互斥量,处于两态之一的变量:解锁和加锁,两个状态可以保证资源访问的串行。 原子性:指一系列操作不可被中断的特性,要么全部执行完成,要么全部没有执行。
2、自旋锁:自旋锁是一种多线程同步的变量,使用自旋锁的线程会反复检查锁变量是否可用,自旋锁不会让出CPU,是一种忙等待状态,即死循环等待锁被释放,自旋锁的效率远高于互斥锁。特点:避免了进程或者线程上下文切换的开销,但是不适合在单核CPU使用。
3、读写锁:是一种特殊的自旋锁,允许多个读操作同时访问资源以提高读性能,但是对写操作是互斥的,即对多读少写的操作效率提升很显著。
4、条件变量:是一种相对比较复杂的线程同步方法,条件变量允许线程睡眠,直到满足某种条件,当满足条件时,可以给该线程信号通知唤醒。
3.8 Linux的进程管理
进程的类型:
前台进程:具有终端,可以和用户交互;
后台进程:没有占用终端,基本不和用户交互,优先级比前台进程低(将需要执行的命令以“&”符号结束);
守护进程:特殊的后台进程,在系统引导时启动,一直运行直到系统关闭(进程名字以“d”结尾的一般都是守护进程),如crond、sshd、httpd、mysqld…
进程的标记:
进程ID:非负整数,进程的唯一标记,每个进程拥有不同的ID;
进程的状态标记:R表示进程处于运行状态,S表示进程处于睡眠状态…
下一章 第四章 内存管理
第四章 内存管理