尽人事,听天命。博主东南大学硕士在读,热爱健身和篮球,乐于分享技术相关的所见所得,关注公众号 @ 飞天小牛肉,第一时间获取文章更新,成长的路上我们一起进步

本文已收录于 CS-Wiki(Gitee 官方推荐项目,现已累计 1.4k+ star),致力打造完善的后端知识体系,在技术的路上少走弯路,欢迎各位小伙伴前来交流学习

 

全文脉络思维导图如下:

1. 什么是进程同步

在多道批处理系统中,多个进程是可以并发执行的,但由于系统的资源有限,进程的执行不是一贯到底的, 而是走走停停,以不可预知的速度向前推进,这就是进程的异步性

那么,进程的异步性会带来什么问题呢?举个例子,如果有 A、B 两个进程分别负责读和写数据的操作,这两个线程是相互合作、相互依赖的。那么写数据应该发生在读数据之前。而实际上,由于异步性的存在,可能会发生先读后写的情况,而此时由于缓冲区还没有被写入数据,读进程 A 没有数据可读,因此读进程 A 被阻塞。

进程同步(synchronization)就是用来解决这个问题的。从上面的例子我们能看出,一个进程的执行可能影响到另一个进程的执行,所谓进程同步就是指协调这些完成某个共同任务的并发线程,在某些位置上指定线程的先后执行次序、传递信号或消息

再举个生活中的进程同步的例子,你想要喝热水,于是你打了一壶水开始烧,在这壶水烧开之前,你只能一直等着,水烧开之后水壶自然会发生响声提醒你来喝水,于是你就可以喝水了。就是说水烧开这个事情必须发生在你喝水之前

注意不要把进程同步和进程调度搞混了:

  • 进程调度是为了最大程度的利用 CPU 资源,选用合适的算法调度就绪队列中的进程。

  • 进程同步是为了协调一些进程以完成某个任务,比如读和写,你肯定先写后读,不能先读后写吧,这就是进程同步做的事情了,指定这些进程的先后执行次序使得某个任务能够顺利完成。

2. 什么是进程互斥

同样的,也是因为进程的并发性,并发执行的线程不可避免地需要共享一些系统资源,比如内存、打印机、摄像头等。举个例子:我们去学校打印店打印论文,你按下了 WPS 的 “打印” 选项,于是打印机开始工作。 你的论文打印到一半时,另一位同学按下了 Word 的 “打印” 按钮,开始打印他自己的论文。想象一下如果两个进程可以随意的、并发的共享打印机资源,会发生什么情况?

显然,两个进程并发运行,导致打印机设备交替的收到 WPS 和 Word 两个进程发来的打印请求,结果两篇论文的内容混杂在一起了。

进程互斥(mutual exclusion)就是用来解决这个问题的。当某个进程 A 在访问打印机时,如果另一个进程 B 也想要访问打印机,它就必须等待,直到 A 进程访问结束并释放打印机资源后,B 进程才能去访问。

实际上,像上述的打印机这种在一个时间段内只允许一个进程使用的资源(这也就是互斥的意思),我们将其称为临界资源,对临界资源进行访问的那段代码称为临界区

通俗的对比一下进程互斥和进程同步:

  • 进程同步:进程 A 应在进程 B 之前执行

  • 进程互斥:进程 A 和进程 B 不能在同一时刻执行

从上不难看出,进程互斥是一种特殊的进程同步,即逐次使用临界资源,也是对进程使用资源的先后执行次序的一种协调。

3. 常见的进程同步与互斥机制

常见的进程同步与互斥机制有两种:

  • 信号量与 PV 操作

  • 管程

① 信号量与 PV 操作

包交包会!看完下面这段解释你绝对能够明白 PV 操作是啥。

1965年,荷兰学者 Dijkstra 提出了一种卓有成效的实现进程同步和互斥的方法 — 信号量机制(Semaphore)。信号量其实就是一个变量 ,我们可以用一个信号量来表示系统中某种资源的数量,比如:系统中只有一台打印机,就可以设置一个初值为 1 的信号量。

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

1)P 操作:将信号量值减 1,表示申请占用一个资源。如果结果小于 0,表示已经没有可用资源,则执行 P 操作的进程被阻塞。如果结果大于等于 0,表示现有的资源足够你使用,则执行 P 操作的进程继续执行。

可以这么理解,当信号量的值为 2 的时候,表示有 2 个资源可以使用,当信号量的值为 -2 的时候,表示有两个进程正在等待使用这个资源。不看这句话真的无法理解 V 操作,看完顿时如梦初醒。

2)V 操作:将信号量值加 1,表示释放一个资源,即使用完资源后归还资源。若加完后信号量的值小于等于 0,表示有某些进程正在等待该资源,由于我们已经释放出一个资源了,因此需要唤醒一个等待使用该资源(就绪态)的进程,使之运行下去。

我觉得已经讲的足够通俗了,不过对于 V 操作大家可能仍然有困惑,下面再来看两个关于 V 操作的问答:

问:信号量的值 大于 0 表示有临界资源可供使用,这个时候为什么不需要唤醒进程

答:所谓唤醒进程是从就绪队列(阻塞队列)中唤醒进程,而信号量的值大于 0 表示有临界资源可供使用,也就是说这个时候没有进程被阻塞在这个资源上,所以不需要唤醒,正常运行即可。

问:信号量的值 等于 0 的时候表示没有临界资源可供使用,为什么还要唤醒进程

答:V 操作是先执行信号量值加 1 的,也就是说,把信号量的值加 1 后才变成了 0,在此之前,信号量的值是 -1,即有一个进程正在等待这个临界资源,我们需要唤醒它。

信号量和 PV 操作具体的定义如下:

实现进程互斥

两步走即可实现进程的互斥:

  • 定义一个互斥信号量,并初始化为 1

  • 把对于临界资源的访问置于 P 操作和 V 操作之间

P 操作和 V 操作必须成对出现。缺少 P 操作就不能保证对临界资源的互斥访问,缺少 V 操作就会导致临界资源永远得不到释放、处于等待态的进程永远得不到唤醒。

实现进程同步

回顾一下进程同步,就是要各并发进程按要求有序地运行。

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

如果 P2 的 “代码4” 要基于 P1 的 “代码1” 和 “代码2” 的运行结果才能执行,那么我们就必须保证 “代码4” 一定是在 “代码2” 之后才会执行。

使用信号量和 PV 操作实现进程的同步也非常方便,三步走:

  • 定义一个同步信号量,并初始化为当前可用资源的数量

  • 在优先级较的操作的面执行 V 操作,释放资源

  • 在优先级较的操作的面执行 P 操作,申请占用资源

配合下面这张图直观理解下:

生产者和消费者问题

下面我们利用信号量和 PV 操作来解决经典的进程同步和互斥问题:生产者和消费者问题。

【问题描述】:系统中有一组生产者进程和一组消费者进程,生产者进程每次生产一个产品放入缓冲区,消费者进程每次从缓冲区中取出一个产品并使用。任何时刻,只能有一个生产者或消费者可以访问缓冲区。

由题可知,生产者、消费者共享一个初始为空、大小为 n 的缓冲区,我们从题目中提炼出同步与互斥关系:

  • 同步关系 1:只有缓冲区没满时(优先级高),生产者才能把产品放入缓冲区(优先级低),否则必须等待

  • 同步关系 2:只有缓冲区不空时(优先级高),消费者才能从中取出产品(优先级低),否则必须等待

  • 互斥关系:缓冲区是临界资源,各进程必须互斥地访问。

既然这个题目有两个同步关系和一个互斥关系,那么我们就需要两个同步信号量和一个互斥信号量:

  • empty:同步信号量(对应同步关系 1),表示生产者还能生产多少,即还能放入缓冲区多少产品,该数量小于等于 0,则生产者不能进行生产。 初始化为 n。

  • full:同步信号量(对应同步关系 2),表示消费者还能从缓冲区取出多少,即当前缓冲区已有产品的数量,该数量小于等于 0,则消费者不能进行读取。初始化为 0。

  • mutex:互斥信号量,实现对缓冲区的互斥访问。初始化为 1。

代码如下,注意各个 PV 操作的配对:

② 管程

管程有一个重要特性:在一个时刻只能有一个进程使用管程。进程在无法继续执行的时候不能一直占用管程,否则其它进程将永远不能使用管程。也就是说管程天生支持进程互斥

其实使用管程是能够实现信号量的,并且也能用信号量实现管程。但是管程封装的比较好,相比起信号量来需要我们编写的代码更少,更加易用,这也就是 Java 采用管程机制的原因,synchronized 关键字及 wait()notify()notifyAll() 这三个方法都是管程的组成部分。把管程翻译为 Java 领域的语言,就是管理类的成员变量和成员方法,让这个类是线程安全的。再详细的部分就不再深究了,溜了溜了。

关注公众号 | 飞天小牛肉,即时获取更新

  • 博主东南大学硕士在读,利用课余时间运营一个公众号『 飞天小牛肉 』,2020/12/29 日开通,专注分享计算机基础(数据结构 + 算法 + 计算机网络 + 数据库 + 操作系统 + Linux)、Java 基础和面试指南的相关原创技术好文。本公众号的目的就是让大家可以快速掌握重点知识,有的放矢。希望大家多多支持哦,和小牛肉一起成长

  • 并推荐个人维护的开源教程类项目: CS-Wiki(Gitee 推荐项目,现已累计 1.4k+ star), 致力打造完善的后端知识体系,在技术的路上少走弯路,欢迎各位小伙伴前来交流学习 ~

看完了进程同步与互斥机制,我终于彻底理解了 PV 操作的更多相关文章

  1. 终于把你必须知道的.NET看完了

    终于把你必须知道的.NET看完了,第二步就是把精通ASP.NET MVC3框架这本书搞定,练习MVC3的使用,并把EF,LINQ也练习一下,期间要做一个项目“多用户微信公众平台”项目,最近微信公众平台 ...

  2. HTTP协议漫谈 C#实现图(Graph) C#实现二叉查找树 浅谈进程同步和互斥的概念 C#实现平衡多路查找树(B树)

    HTTP协议漫谈   简介 园子里已经有不少介绍HTTP的的好文章.对HTTP的一些细节介绍的比较好,所以本篇文章不会对HTTP的细节进行深究,而是从够高和更结构化的角度将HTTP协议的元素进行分类讲 ...

  3. 【转】进程同步之信号量机制(pv操作)及三个经典同步问题

    原文地址:http://blog.csdn.net/speedme/article/details/17597373 上篇博客中(进程同步之临界区域问题及Peterson算法),我们对临界区,临界资源 ...

  4. primer看完了

    放假这将近十天吧,终于把C++ Primer中文版第五版大致看完了,然而第四部分(高级主题)还是没有看,感觉那是需要有足够的项目经验再看. 另外,看一遍肯定不够,忘得也会很快,我十分确认今后还会很多次 ...

  5. Nachos-Lab3-同步与互斥机制模块实现

    源码获取 https://github.com/icoty/nachos-3.4-Lab 内容一:总体概述 本实习希望通过修改Nachos系统平台的底层源代码,达到"扩展同步机制,实现同步互 ...

  6. C#本质论第四版-1,抄书才能看下去,不然两三眼就看完了,一摞书都成了摆设。抄下了记忆更深刻

    C#本质论第四版-1,抄书才能看下去,不然两三眼就看完了,一摞书都成了摆设.抄下了记忆更深刻 本书面向的读者 写作本书时,我面临的一个挑战是如何持续吸引高级开发人员眼球的同时,不因使用assembly ...

  7. 【原创】xenomai内核解析--同步互斥机制(一)--优先级倒置

    版权声明:本文为本文为博主原创文章,转载请注明出处.如有错误,欢迎指正.博客地址:https://www.cnblogs.com/wsg1100/ 目录 一.xenomai 资源管理简要 二.优先级倒 ...

  8. <c ss高效开发实战>看完了,Bootstrap学习是关键

    Bootstrap果真给我们带来了很多便利,学习CSS,必须要掌握很多框架和快速学习的方法. 这本书看完了,也写过几篇读书笔记,墙裂推荐.不上书封面了,只上书的导图. 这里说几点学习CSS的心得 1. ...

  9. 跌跌撞撞的看完了《jquery技术内幕》

    今年2月20日买的书,今天是5月26,三个月来,除了周末休息一天,如果没有特殊情况,我都会每晚花两个小时看这本书,以及查各种与jquery源码相关的资料.今天总算是跌跌撞撞的看完了,有点小激动,也有点 ...

随机推荐

  1. linux(7)top命令详细解释

    top命令 Linux top命令用于实时显示 process 的动态. top参数详解 第一行,任务队列信息 系统当前时间:13:52:56 系统开机后到现在的总运行时间:up 66 days,8m ...

  2. Pytest(16)随机执行测试用例pytest-random-order

    前言 通常我们认为每个测试用例都是相互独立的,因此需要保证测试结果不依赖于测试顺序,以不同的顺序运行测试用例,可以得到相同的结果. pytest默认运行用例的顺序是按模块和用例命名的 ASCII 编码 ...

  3. EXCEL序列

  4. The Department of Redundancy Department

    Write a program that will remove all duplicates from a sequence of integers and print the list of un ...

  5. Codeforces Round #625 (Div. 2, based on Technocup 2020 Final Round) B. Journey Planning(映射)

    题意: 已知 n 所城市(从 1 至 n 编号)及其美丽值,选取一条旅行路线,满足路线中两两城市美丽值之差等于编号之差,求所有旅行路线中美丽值的最大值. 思路: 美丽值与编号作差,差值为键,映射累加 ...

  6. Codeforces Round #672 (Div. 2 B. Rock and Lever (位运算)

    题意:给你一组数,求有多少对\((i,j)\),使得\(a_{i}\)&\(a_{j}\ge a_{i}\ xor\ a_{j}\). 题解:对于任意两个数的二进制来说,他们的最高位要么相同要 ...

  7. 牛客编程巅峰赛S1第5场 - 青铜&白银 B.完全平方数的尾巴 (暴力)

    题意:有一个数\(x\),判断其是否能有某个完全平方数$mod$1000得到. 题解:直接写个for判断一下就好了,因为对1000取模,所以枚举到1000即可. 代码: class Solution ...

  8. ASP.Net Core 5.0 MVC中AOP思想的体现(五种过滤器)并结合项目案例说明过滤器的用法

    执行顺序 使用方法,首先实现各自的接口,override里面的方法, 然后在startup 类的 ConfigureServices 方法,注册它们. 下面我将代码贴出来,照着模仿就可以了 IActi ...

  9. 【原创】k8s之job和Cronjob

    1.失败任务 apiVersion: batch/v1 kind: Job metadata: name: bad spec: template: metadata: name: bad spec: ...

  10. SPOJ VLATTICE Visible Lattice Points(莫比乌斯反演)题解

    题意: 有一个\(n*n*n\)的三维直角坐标空间,问从\((0,0,0)\)看能看到几个点. 思路: 按题意研究一下就会发现题目所求为. \[(\sum_{i=1}^n\sum_{j=1}^n\su ...