进程同步和互斥

彩蛋 操作系统总目录 戳我

进程互斥的硬件实现方法

进程互斥的硬件实现方法

  1. 理解各方法的原理
  2. 了解各方法的优缺点
中断屏蔽方法

利用“开 / 关中断指令”实现(与原语的实现思想相同,即在某进程开始访问临界区到结束访问为止都不允许被中断,也就不能发生进程切换,因此也不可能发生两个同时访问临界区的情况)

优点:简单、高效
缺点:不适用于多处理机;只适用于操作系统内核进程,不适用于用户进程(因为开 / 关中断指令 只能运行在内核态,这组指令如果能让用户随意使用会很危险)

TestAndSet指令

简称TS 指令,也有地方称为TestAndSetLock 指令,或TSL 指令 . TSL 指令是用硬件实现的,执行的过程不允许被中断,只能一气呵成。以下是用C语言描述的逻辑

/*
* 布尔型共享变量lock 表示当前临界区是否被加锁
* true表示已加锁,false 表示未加锁
*/
bool TestAndTest(bool *lock){
	bool old;
    old = *lock;
    *lock = true;
    return old;
}
/* 以下是使用TSL指令实现互斥的算法逻辑 */
while(TestAndSet(&lock));/*"上锁" 并 "检查" */
//临界区代码...
lock = false;
//剩余区代码...

若刚开始lock 是false,则 TSL 返回的old 值为false,while 循环条件不满足,直接跳过循环,进入临界区。若刚开始lock 是true,则执行 TLS 后old 返回的值为true,while 循环条件满足,会一直循环,直到当前访问临界区的进程在退出区进行“解锁”。

相比软件实现方法,TSL 指令把“上锁”和“检查”操作用硬件的方式变成了一气呵成的原子操作。

优点:实现简单,无需像软件实现方法那样严格检查是否会有逻辑漏洞;适用于多处理机环境
缺点:不满足让权等待原则,暂时无法进入临界区的进程会占用CPU并循环执行TSL指令,从而导致“忙等”。

Swap指令

有的地方也叫Exchange 指令,或简称XCHG 指令。
Swap 指令是用硬件实现的,执行的过程不允许被中断,只能一气呵成。以下是用C语言描述的逻辑

/* Swap 指令的作用是交换两个变量的值 */
Swap (bool *a ,bool *b){
	bool temp = *a;
    *a = *b;
    *b = temp;
}

bool old = true;
while( old == true )
    Swap(&lock, &old);
//临界区代码...
lock = false;
//剩余区代码...

逻辑上来看Swap 和TSL 并无太大区别,都是先记录下此时临界区是否已经被上锁(记录在ol量上),再将上锁标记lock 设置为true,最后检查 old,如果 old 为false 则说明之前没有别的进程对临界区上锁,则可跳出循环,进入临界区。

优点:实现简单,无需像软件实现方法那样严格检查是否会有逻辑漏洞;适用于多处理机环境
缺点:不满足“让权等待”原则,暂时无法进入临界区的进程会占用CPU并循环执行TSL指令,从而导致“忙等”。

小结

信号量机制

知识总览

进程互斥的四种软件实现方式(单标志法、双标志先检查、双标志后检查、Peterson算法)
进程互斥的三种硬件实现方式(中断屏蔽方法、TS/TSL指令、Swap/XCHG指令)

  1. 在双标志先检查法中,进入区的“检查”、“上锁”操作无法一气呵成,从而导致了两个进程有可能同时进入临界区的问题;

  2. 所有的解决方案都无法实现让权等待

1965年,荷兰学者Dijkstra提出了一种卓有成效的实现进程互斥、同步的方法——信号量机制


用户进程可以通过使用操作系统提供的一对原语来对信号量进行操作,从而很方便的实现了进程互斥、进程同步。

信号量其实就是一个变量(可以是一个整数,也可以是更复杂的记录型变量) ,可以用一个信号量来表示系统中某种资源的数量,比如:系统中只有一台打印机,就可以设置一个初值为1 的信号量。

一对原语:wait(S) 原语和signal(S) 原语,可以把原语理解为我们自己写的函数,函数名分别为wait
和signal,括号里的信号量S 其实就是函数调用时传入的一个参数。

wait、signal 原语常简称为P、V操作(来自荷兰语proberen 和verhogen)。因此,做题的时候常把wait(S) 、signal(S) 两个操作分别写为P(S) 、V(S)

信号量机制——整型信号量

用一个整数型的变量作为信号量,用来表示系统中某种资源的数量。

与普通整数变量的区别:对信号量的操作只有三种,即初始化、P操作、V操作

Eg :某计算机系统中有一台打印机…

信号量机制——记录型信号量

整型信号量的缺陷是存在“忙等”问题,因此人们又提出了“记录型信号量”,即用记录型数据结构表示的信号量。

wait(S) 、signal(S) 也可以记为P(S) 、V(S) ,这对原语可用于实现系统资源的“申请”和“释放”。

S.value 的初值表示系统中某种资源的数目。对信号量S 的一次P 操作意味着进程请求一个单位的该类资源,因此需要执行S.value-- ,表示资源数减1,当S.value < 0 时表示该类资源已分配完毕,因此进程应调用block 原语进行自我阻塞(当前运行的进程从运行态 ----> 阻塞态),主动放弃处理机,并插入该类资源的等待队列S.L 中。可见,该机制遵循了“让权等待”原则,
不会出现“忙等”现象。

对信号量S 的一次V 操作意味着进程释放一个单位的该类资源,因此需要执行S.value++,表示资源数加1,若加1后仍是 S.value <= 0,表示依然有进程在等待该类资源,因此应调用wakeup 原语唤醒等待队列中的第一个进程(被唤醒进程从阻塞态 ----> 就绪态)。

小结

用信号量机制实现

知识总览

在这里插入图片描述

Tips:不要一头钻到代码里,要注意理解信号量背后的含义,一个信号量对应一种资源

信号量的值= 这种资源的剩余数量(信号量的值如果小于0,说明此时有进程在等待这种资源)

P( S ) —— 申请一个资源S,如果资源不够就阻塞等待
V( S ) —— 释放一个资源S,如果有进程在等待该资源,则唤醒一个进程

信号量机制实现进程互斥
  1. 分析并发进程的关键活动,划定临界区(如:对临界资源打印机的访问就应放在临界区)
  2. 设置互斥信号量mutex,初值为1
  3. 在进入区P(mutex)——申请资源
  4. 在退出区V(mutex)——释放资源

理解:信号量mutex 表示“进入临界区的名额”

注意:

  • 对不同的临界资源需要设置不同的互斥信号量。
  • P、V操作必须成对出现。缺少P(mutex) 就不能保证临界资源的互斥访问。缺少V(mutex) 会导致资源永不被释放,等待进程永不被唤醒。
信号量机制实现进程同步

进程同步:要让各并发进程按要求有序地推进。

比如,P1、P2 并发执行,由于存在异步性,因此二者交替推进的次序是不确定的。若P2 的“代码4”要基于 P1 的“代码1”和“代码2”的运行结果才能执行,那么我们就必须保证“代码4”一定是在“代码2”之后才会执行。

这就是进程同步问题,让本来异步并发的进程互相配合,有序推进。

用信号量实现进程同步:

  1. 分析什么地方需要实现“同步关系”,即必须保证“一前一后”执行的两个操作(或两句代码)
  2. 设置同步信号量S, 初始为0
  3. 在“前操作”之后执行V(S)
  4. 在“后操作”之前执行P(S)

技巧口诀:前V后P

信号量机制实现前驱关系

进程P1 中有句代码S1,P2 中有句代码S2 ,P3中有句代码S3 …… P6 中有句代码S6。这些代码要求
按如下前驱图所示的顺序来执行:

其实每一对前驱关系都是一个进程同步问题(需要保证一前一后的操作)因此,

  1. 要为每一对前驱关系各设置一个同步信号量
  2. 在“前操作”之后对相应的同步信号量执行V 操作
  3. 在“后操作”之前对相应的同步信号量执行P 操作

小结

在这里插入图片描述

信号量专题

生产者消费者问题
吸烟者问题
读者 - 写者问题
哲学家就餐

管程

知识总览

为什么要引入管程
  • 信号量机制存在的问题:编写程序困难、易出错

能不能设计一种机制,让程序员写程序时不需要再关注复杂的PV操作,让写代码更轻松呢?

1973年,Brinch Hansen 首次在程序设计语言 (Pascal)中引入了“管程”成分---------------------一种高级同步机制

管程的定义和基本特征
  • 组成

管程是一种特殊的软件模块,有这些部分组成:

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

管程的基本特征:

  1. 局部于管程的数据只能被局部于管程的过程所访问;
  2. 一个进程只有通过调用管程内的过程才能进入管程访问共享数据;
  3. 每次仅允许一个进程在管程内执行某个内部过程。
拓展1:用管程解决生产者消费者问题

在这里插入图片描述

引入管程的目的无非就是要更方便地实现进程互斥和同步。

  1. 需要在管程中定义共享数据(如生产者消费者问题的缓冲区)
  2. 需要在管程中定义用于访问这些共享数据的“入口”——其实就是一些函数(如生产者消费者问题中,可以定义一个函数用于将产品放入缓冲区,再定义一个函数用于从缓冲区取出产品)
  3. 只有通过这些特定的“入口”才能访问共享数据
  4. 管程中有很多“入口”,但是每次只能开放其中一个“入口”,并且只能让一个进程或线程进入(如生产者消费者问题中,各进程需要互斥地访问共享缓冲区。管程的这种特性即可保证一个时间段内最多只会有一个进程在访问缓冲区 注意:这种互斥特性是由编译器负责实现的,程序员不用关心)
  5. 可在管程中设置条件变量及等待 / 唤醒操作以解决同步问题。可以让一个进程或线程在条件变量上等待(此时,该进程应先释放管程的使用权,也就是让出“入口”);可以通过唤醒操作将等待在条件变量上的进程或线程唤醒。

程序员可以用某种特殊的语法定义一个管程(比如 : monitor ProducerConsumer …… end monitor; ),之后其他程序员就可以使用这个管程提供的特定“入口”很方便地使用实现进程同步 / 互斥了。封装思想

拓展2:Java 中类似于管程的机制

Java 中,如果用关键字synchronized 来描述一个函数,那么这个函数同一时间段内只能被一个线程调用

每次只能有一个线程进入insert 函数,如果多个线程同时调用insert 函数,则后来者需要排队等待

小结

d monitor; ),之后其他程序员就可以使用这个管程提供的特定“入口”很方便地使用实现进程同步 / 互斥了。封装思想

拓展2:Java 中类似于管程的机制

Java 中,如果用关键字synchronized 来描述一个函数,那么这个函数同一时间段内只能被一个线程调用

[外链图片转存中…(img-3v9R5xv1-1620395878015)]

每次只能有一个线程进入insert 函数,如果多个线程同时调用insert 函数,则后来者需要排队等待

小结

在这里插入图片描述

  • 17
    点赞
  • 126
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值