操作系统——4.进程同步、进程互斥、信号量机制、管程


JAVA后端开发知识总结(持续更新…)


进程同步、进程互斥、信号量机制、管程


B站:《王道考研 操作系统》
《现代操作系统》



一、进程同步与互斥

1.1 进程同步

  由于进程的异步性,各个并发执行的进程以独立且不可预知的速度向前推进。当需要进程按照某种特定的顺序执行时(例如之前所说的管道通信,向管道写数据和从管道读数据的进程是并发执行的,但必须保证写数据先执行,读数据进程后执行),需要依靠操作系统提供的进程同步机制来完成。

1.2 进程互斥

  进程的“并发”需要“共享”的支持,各个并发的进程需要共享一些系统资源。资源共享分为互斥共享方式同时共享方式

  将一个时间段内只允许一个进程使用的资源称为临界资源(如物理设备、部分变量、数据、内存缓冲区等)。
  对临界资源的访问,必须互斥进行,即一个进程访问临界资源时,另一个进程想要访问临界必须要等待。

  • 对临界资源的互斥访问在逻辑上可以分为以下四个步骤

在这里插入图片描述

  • 对临界资源的互斥访问需要遵循以下四个原则
  1. 空闲让进:临界区空闲时,可以允许一个请求进入临界区的进程立即进入临界区。
  2. 忙则等待:当已有进程进入临界区时,其它试图进入临界区的进程必须等待。
  3. 有限等待:对请求访问的进程,应保证能在有限时间内进入临界区(保证不会饥饿)。
  4. 让权等待:当进程不能进入临界区时,应立即释放处理机,防止进程忙等待。

二、进程互斥的实现方法

2.1 软件实现方法

  • 单标志法:

  设定一个turn标志(允许访问的标识号),当一个进程在访问完临界区后会将使用临界区的权限转交给另一个进程,即每个进程进入临界区的权限只能被另一个进程赋予。因此违背空闲让进原则

在这里插入图片描述

  • 双标志先检查法:

  设置一个布尔型数组flag[n],数组中各个元素用来标记各个进程想要进入临界区的意愿。每个进程在进入临界区前都检查是否有其它进程想要进入临界区,没有的话就将自己对应的flag[i]修改为true,开始访问临界区。
  但在并发的情况下,由于进程切换原因,可能导致两个进程同时进入临界区,违背了忙则等待的原则(进入区检查和上锁不是原子操作)。

  • 双标志后检查法:

  与双标志先检查法类似,只是将上锁提前到了检查前(先设置flag),但这样可能导致多个线程都无法进入临界区。违背了空闲让进和有限等待原则

在这里插入图片描述

  • Peterson算法

  Peterson算法的关键思想是,让进程争抢进入临界区的问题转换成进程主动让其它进程先使用的问题。同样定义了布尔数组来表示进入意愿,也定义了turn标志表示优先让哪个进程进入。达到了多个进程都有进入临界区的意愿时,进程间的“孔融让梨”的效果。但仍然没有遵循让权等待原则

在这里插入图片描述

2.2 硬件实现方法

  • 中断屏蔽方法:

  之前所提到的在内核态下使用开/关中断指令实现进程互斥访问临界区。但不适用于多处理机,并且只适用于操作系统内核进程。

  • TestAndSet(TS / TSL指令):

  TestAndSet是硬件实现的,定义了一个布尔型的共享变量lock来表示当前临界区是否被加锁。缺点是不满足让权等待原则,无法进入临界区的进程占用处理机执行TSL指令(一直在while循环中)。下面是C语言描述的逻辑:

在这里插入图片描述

  • Swap指令:类似于TSL指令,操作硬件,只是实现方式不一样,且同样不满足让权等待原则。

在这里插入图片描述

三、信号量机制——可关注高并发的相关知识

3.1 基本概念

解决上述方法的两个问题

  1. 进入区的“检查”、“上锁” 操作无法一气呵成,不是原子操作。
  2. 所有的解决方案都无法实现“让权等待”原则。

信号量其实是一个变量 ,可以用一个信号量来表示系统中某种资源的数量。用户进程可以通过使用操作系统提供的一对原语wait和signal原语:P、V操作)来对信号量进行操作,从而很方便地实现进程互斥、进程同步。

  • 整型信号量:用一个整数型变量作为信号量,用于表示系统中某种资源的数量。与软件实现中的双标志先检查法类似(先检查,后上锁),只是信号量是通过原语进程实现的,是原子操作。但还是无法解决让权等待的问题(while一直循环)

在这里插入图片描述

  • 记录型信号量:增加了一个等待队列,使得无法获取资源的线程能够被阻塞,等待资源充足后被唤醒,解决了让权等待问题。

在这里插入图片描述

3.2 信号量机制实现进程互斥与同步

  • 实现进程互斥——Semaphore进行声明

  临界区可以看作一种特殊的系统资源,用互斥信号量mutex来表示。然后在临界区前进行P(mutex),在临界区后执行V(mutex),来实现基于信号量的进程互斥。对不同的临界资源需要设置不同的互斥信号量,P、V操作必须成对出现

在这里插入图片描述

  • 实现进程同步——Semaphore进行声明

  具体实现是设置一个同步信号量S=0 。在“前操作”之后执行V(S) ,在“后操作”之前执行P(S)
   若先执行到V(S)操作,则S++后S=1。之后当执行到P(S) 操作时,由于S=1,表示有可用资源,会执行S–,S的值变回0,P2进程不会执行block原语,而是继续往下执行代码。
   若先执行到P(S) 操作,由于S=0,S–后S=-1,表示此时没有可用资源,因此P操作中会执行block原语,主动请求阻塞。之后当执行完当前任务,继而执行V(S)操作,S++,使S变回0。由于此时有进程在该信号量对应的阻塞队列中,因此会在V操作中执行wakeup原语,唤醒阻塞进程。总结下就是,实现同步,前V后P

3.3 生产者-消费者问题

   生产者-消费者问题存在三对关系——两个同步,一个互斥。因为缓冲区是临界资源,各进程必须是互斥访问的。并且消费者要消费数据必须在生产者生产数据后进行,缓冲区满后需要先消费再生产,都是需要同步的。

在这里插入图片描述

利用信号量实现

在这里插入图片描述

由于P操作可能使得进程进入阻塞状态,实现互斥的P操作一定要放在实现同步的P操作后,否则会出现死锁。

3.4 线程同步

   线程同步是两个或多个共享关键资源的线程的并发执行,应该同步线程以避免关键资源的使用冲突。操作系统一般有下面三种线程同步的方式:

  1. 互斥量(Mutex):采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。比如 Java 中的 synchronized和各种 Lock都是这种机制。
  2. 信号量(Semphares) :它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量。
  3. 事件(Event):Wait/Notify,通过通知操作的方式来保持多线程同步,还可以方便地实现多线程优先级的比较。

四、管程(monitor)

   管程是一种高级的同步机制,用于解决信号量编写困难、易出错的问题。Java中的synchronized实现就是类似于管程的机制。管程是一种特殊的软件模块,由以下部分组成(类似于面向对象中的类):

  1. 局部于管程的共享数据结构说明;
  2. 对该数据结构进行的一组过程(函数)
  3. 对局部于管程的共享数据结构设置初始值的语句;
  4. 管程的名字。

管程的基本特征

  1. 局部于管程的数据只能被局部于管程的过程访问;
  2. 一个进程只有通过调用管程内的过程才能进入管程访问共享数据;
  3. 每次仅允许一个进程在管程内执行某个内部过程
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值