文章目录

  • 第六章:进程同步
    • 6.1 背景
    • 6.2 临界区问题
    • 6.3 Peterson算法
    • 6.4 硬件同步
    • 6.5 信号量
      • 6.5.1 用法
      • 6.5.2 实现
      • 6.5.3 死锁与饥饿
    • 6.6 经典同步问题
      • 6.6.1 有限缓冲问题
      • 6.6.2 读者---写者问题
      • 6.6.3 哲学家进餐问题
    • 6.7 管程

第六章:进程同步

6.1 背景

在多进程状态下,共享数据的并发访问可能会产生数据的不一致。这章会讨论各种机制,以确保共享同一逻辑地址空间的协作进程可以有序地执行

之前提到了生产者-----消费者问题,采用了共享内存的方法
虽然生产者和消费者程序各自都正确,但是在并发运行时,可能会产生不正确的结果

比如counter++这条语句,在机器中实际上是这样实现的
register1为CPU局部寄存器

  • register1 = counter
  • register1 = register1 + 1
  • count = register1

count–语句实际上是这样实现的

  • register2 = counter
  • register2 = register2 - 1
  • counter = register2

而并发执行counter++和counter–相当于按任意顺序交替执行上面的语句,比如以下的执行方式
(counter的初值为5)

原本实现counter++和counter–得到的结果是5,但是这里得到的结果却是4
如果将T4和T5做交换,得到的结果会是6

在上面这种情况中,多个进程并发访问和操作同一数据且执行结果与访问发生的特定顺序有关,这样的情况被称为竞争条件(race condition)

6.2 临界区问题

  • 每个进程都有一个代码片段被称为临界区,在这个临界区内,进程可能改变共同变量,更新一个表,写一个文件等
  • 操作系统的重要特征是当一个进程进入临界区时,没有其它进程可被允许在临界区中执行
  • 临界区问题(critical-section problem)时设计一个以便进程协作的协议。每个进程必须请求允许进入其临界区。实现这一请求的代码片段被称为进入区,临界之后可有退出区,其他代码为剩余区

临界区需要满足三个条件

  • 互斥:如果一个进程在其临界区中执行,那么其它进程不能进入临界区
  • 前进:如果没有进程在临界区执行,那么只有那些不在剩余区的进程可以参加选择,确定谁能进入下一个临界区
  • 有限等待:从一个进程做出进入临界区的请求,直到该请求允许为止,其他进程允许进入其临界区的次数有上限

6.3 Peterson算法

  1. Peterson算法是一个基于软件的临界区问题的解答
  2. Peterson算法需要在两个进程(Pi, Pj)之间共享两个数据项:int turn; boolean flag[2];

变量turn代表了哪个进程可以进入其临界区,数组flag表示哪个进程想进入临界区
注意:上面这个图仅仅演示了进程Pi的结构,如果是进程Pj的话,相应的i和j的值需要改变

6.4 硬件同步

1.一般来说,任意临界区问题的解决方法都需要使用“锁”这个工具
2.一个进程在进入临界区之前必须得到锁,而在退出临界区时释放锁

3.本节会介绍一些简单的硬件指令,并描述如何利用它们来解决临界区问题
4.对于单处理器系统,解决临界区问题比较简单:在修改共享变量时禁止中断出现即可
5.对于多处理器系统,由于涉及消息的传递,如果选择关中断,那么会降低系统的效率
6.许多现代计算机系统提供了特殊的硬件指令允许原子地(不可中断地)检查和修改字地内容或交换两个字的内容。可以使用这些特殊指令来解决临界区问题

例1:指令TestAndSet()

boolean类型的变量lock初始值为false

这个指令的执行是原子的,当一个进程进入临界区时,其它进程不能进入临界区。

例2:Swap指令

布尔类型变量lock,初始化为false

这个指令同样是原子执行的,与上面的指令类似

这两个指令要求完全理解并掌握写法

6.5 信号量

上一节描述了基于硬件的临界区问题的解决方案,但对于程序员来说,使用比较复杂,因此我们可以使用信号量这个工具

信号量S是一个整型变量,除了初始化以外,只能通过两个标准原子操作来访问
这两个原子操作分别是:wait(),signal(),这两个操作也被称为P和V(来源是荷兰语)

wait()的定义可表示为:

wait(S)
{/*忙等*/while(S <= 0);s--;
}

signal()的定义可表示为:

signal(S)
{s++;
}

在这两个操作中,对信号量S的修改必须不可分地执行,当一个进程修改信号变量的时候,不能有其它进程同时修改同一信号量的值

6.5.1 用法

操作系统将信号量区分为计数信号量和二进制信号量。计数信号量的值域不受限制,二进制信号量的值只能为0或1。有的系统将二进制信号量称为互斥锁

使用二进制信号量处理多进程的临界区问题,这n个进程共享一个信号量mutex,mutex的初始值为1

do
{waiting(mutex);//进入临界区//临界区代码片段signal(mutex);//剩余区//剩余区代码
}while(TRUE);

具体的执行流程要求完全掌握

6.5.2 实现

  • 上面定义的信号量的缺点是需要忙等待(busy waiting)
  • 当一个进程在临界区内时,其它要进入临界区的进程必须进行无限循环并忙等
  • 为了克服忙等,需要修改信号量操作wait()和signal()的定义。

需要定义一个新的信号量,信号量的结构如下

typedef struct
{int value;struct process* list;
}semaphore;

每个信号量都有一个int类型的value和一个进程列表list。当一个进程必须等待信号量时,就加入到进程链表上,而signal()则会唤醒其中的一个进程

信号量wait()的新定义

wait(semaphore* s)
{s->value--;//如果此时临界区中有进程if(s->value < 0){//将这个进程添加到list列表中list.add(p);//进程阻塞block();}
}

信号量signal()的新定义

signal(semaphore* s)
{s->value++;if(s->value <= 0){//将一个进程从list列表中移除list.del(p);//唤醒在list中的一个进程wakeup(p);}
}

注意

  1. 在本实现中,信号量value的值可能为负值
  2. 如果信号量的值为负,那么其绝对值就是等待该信号量的进程的个数(比如value = -1,则队列长度为1,正在等待的进程数为1)
  3. 信号量的关键之处在于它们是原子地执行的。
  4. 实际上wait和signal的代码是被包装在之前的TestAndLock指令当中的,以保证实现原子地执行

6.5.3 死锁与饥饿

两个或多个进程无限地等待一个事件,而这个事件只能由这些等待进程置之一产生,这些进程就被称为死锁

例:由P0和P1组成的系统,每个都访问信号量S和Q,且这两个信号量的初值均为1

   P0                P1
wait (S) ;      wait (Q);
wait (Q) ;      wait (S) ;
signal(S);      signal (Q) ;
signal (Q);     signal(S);

假设P0先执行wait(S),接着P1执行wait(Q)。
这里P0执行wait(Q)后必须等待P1执行signal(Q),当P1执行wait(S)时,它必须等待P0执行signal(S),因此两个进程陷入死锁

无限期阻塞饥饿,指的是进程在信号量内无限期等待

6.6 经典同步问题

6.6.1 有限缓冲问题

假定缓冲池有n个缓冲项,每个缓冲项能存一个数据项
信号量mutex初始值为1,信号量empty初始值为n和full初始值为0

生产者进程

do
{wait(empty);wait(mutex);//将生产的东西添加到缓冲区signal(mutex);signal(full);}while(1);

消费者进程

do
{wait(full);wait(mutex);//在缓冲区消费signal(mutex);signal(empty);}while(1);

该程序通过信号量的wait和signal方法可以实现:当缓冲区为空时,消费者进程处于等待状态,当缓冲区满时,生产者进程处于等待状态
要求理解清楚这个程序,并能自己独立写出

6.6.2 读者—写者问题

一个数据库可能被多个进程所共享,有的进程负责读(称为读者),有的数据库负责写(称为写者)
如果两个读者同时访问数据库,不会产生问题,但是一个写者和另一个进程同时访问数据库,则可能出现问题

在这个问题中,信号量mutex和wrt的初始值为1,readcount初始值为0
信号量mutex用于确保在修改readcount时互斥
readcount用于表示当前有多少个进程正在读
wrt信号量使写者互斥

写者进程

do
{wait(wrt);//写操作signal(wrt);
}while(1);

读者进程

do
{wait(mutex);readcount++;//如果是第一个读进程if(readcount == 1){//保证在写时无法读,在读时无法写wait(wrt);}signal(mutex);//写操作wait(mutex);readcount--;if(readcount == 0){signal(wrt);}signal(mutex);
}while(1);

这个程序的核心是readcount,要求完全理解程序原理并独立写出

6.6.3 哲学家进餐问题

有5个哲学家,他们的一生用于思考和吃饭,哲学家共用一张圆桌,圆桌的中间是米饭,总共有五只筷子
一个哲学家每次试图拿起他旁边的两个筷子,只有拿起两只筷子,才能吃饭

使用信号量chopsticks[i]表示筷子,总共有5支筷子

哲学家i的进程结构

do
{wait(chopsticks[i]);wait(chopsticks[(i+1)%5]);//哲学家吃饭signal(chopsticks[i]);signal(chopsticks[(i+1)%5]);//哲学家思考
}while(1);

6.7 管程

这一部分由于老师生病请假,没有讲,因此这一部分是自学的。
当然,这一部分属于边缘内容,不太重要

虽然信号量提供了一种方便而有效的机制用于处理进程同步,但是如果不正确使用信号量,仍然会导致出现时序问题

比如以下几种错误情况

  • 交换wait(mutex)和signal(mutex)的顺序
  • 写了两个wait(mutex)
  • wait和signal函数只写一个的情况
  • wait和signal函数都没写

如果出现以上几种情况,则可能出现死锁并破坏互斥机制
为了解决上面的错误,提出了管程类型

操作系统概念笔记——第六章:进程同步相关推荐

  1. 操作系统概念_第六章_进程同步

    概述 临界区问题 Peterson算法 硬件同步 经典同步问题 生产者-消费者问题 读者-写者问题 哲学家进餐问题 信号量 信号量的使用 解决互斥问题 解决资源申请问题 解决同步问题 信号量的实现 死 ...

  2. 操作系统学习笔记 第六章:设备管理(王道考研)

    本文章基于网课: 2019 王道考研 操作系统 考试复习推荐资料:操作系统复习总结 - 百度文库 (baidu.com) 需要相关电子书的可以关注我的公众号BaretH后台回复操作系统 第一章:操作系 ...

  3. 《金融学》笔记 第六章 金融机构

    <金融学>笔记 第六章 金融机构 前言 在<<金融学>笔记>中开了一个头,现在完善具体细节. 金融范畴篇 第一章 货币的本质 第二章 货币制度 第三章 信用.利息和 ...

  4. 深入理解 C 指针阅读笔记 -- 第六章

    Chapter6.h #ifndef __CHAPTER_6_ #define __CHAPTER_6_/*<深入理解C指针>学习笔记 -- 第六章*/typedef struct __p ...

  5. Unix原理与应用学习笔记----第六章 文件的基本属性2

    Unix原理与应用学习笔记----第六章 文件的基本属性2 改变文件权限命令:chmod 提示:文件或目录创建后,就被赋予一组默认的权限.所有的用户都有读,只有文件的所有者才有写. 相对权限设置 Ch ...

  6. 《Go语言圣经》学习笔记 第六章 方法

    <Go语言圣经>学习笔记 第六章 方法 目录 方法声明 基于指针对象的方法 通过嵌入结构体来扩展类型 方法值和方法表达式 示例:Bit数组 封装 注:学习<Go语言圣经>笔记, ...

  7. 《疯狂Java讲义》学习笔记 第六章 面向对象(下)

    <疯狂Java讲义>学习笔记 第六章 面向对象(下) 6.1包装类 基本数据类型 包装类 byte Byte short Short int Integer long Long char ...

  8. 《信息与编码》考试复习笔记6----第六章连续信源熵和信道容量(考点在连续信道容量)

    系列文章链接目录 一.<信息与编码>考试复习笔记1----第一章概论 二.<信息与编码>考试复习笔记2----第二章离散信息源 三.<信息与编码>考试复习笔记2-- ...

  9. 《Python从入门到实践》读书笔记——第六章 字典

    <Python从入门到实践>读书笔记--第六章 字典 1. 一个简单的字典 alien_0 = {'color': 'green', 'points': 5}print(alien_0[' ...

最新文章

  1. golang 传值 传引用 简介
  2. 以网易严选为例,人工智能实战系列之预训练语言模型
  3. Hadoop学习之MapReduce(三)
  4. java实现mysql的主从切换(第二部分)
  5. 用备份进行Active Directory的灾难重建:Active Directory系列之三
  6. 【文文殿下】网络流学习笔记
  7. SIEM部署失败的五大原因
  8. 企业内部在centos7.2系统中必杀技NTP时间服务器及内网服务器时间同步(windows和linux客户端同步)...
  9. vue-promise-axios
  10. 学习人工智能的头四个月
  11. Jmeter(十一)测试监听
  12. MAC可以在.zshrc中修改PATH
  13. html5 查询展示页面,基于Html5的可视化展示页面自动发布方法及系统与流程
  14. 计算机视觉 | 面试题:26、LBP算法原理
  15. DTcms-【无限级别分类设计】
  16. pyinstaller打包py文件为单个文件或多个文件
  17. 宜家开发中心东亚区完成在中国的全新升级;牙科巨头卡瓦集团上海创新卓越中心正式启动 | 美通企业日报...
  18. 互联网产品三大需求文档:BRD、MRD、PRD
  19. TextView 悬挂缩进实现及解析
  20. Windows下自动同步工具SyncToy的使用与定时执行部署

热门文章

  1. 【程序8】乒乓球比赛赛程安排
  2. 数据库课程设计个人总结报告
  3. signature=2166ff43f35436f31c078e6b6e5839fe,10/16/03: Form 8-K (Transcript Slide Presentation)
  4. emacs ido mode
  5. [ecshop 资料 ]ecshop 怎么实现购物满200元免运费
  6. MATLAB调用LINGO程序并交换数据
  7. 关于“大局观”的一些思考
  8. 平移变换、旋转变换、放射变换、射影变换8自由度等基础理论
  9. 【考研】设计求二叉树 T 的 WPL 算法(2014-408真题)
  10. 【强大的数据迁移和恢复解决方案】KernelApps及其产品介绍