文章目录

  • 一、背景
  • 二、 临界区(Critical-Section)
    • 理论上的解决方案要满足(单核状态):
    • Peterson's Solution
      • 进程的情况
      • 简单的形式?
  • 三、 硬件同步机制(Synchronization Hardware)
    • TestAndSet Instruction
    • Swap Instruction
  • 四. 信号量(Semaphores)
    • Semaphore的版本
    • Semaphore Implementation
      • busy waiting
      • no busy waiting
    • Deadlock & Starvation(死锁和饿死)
  • 五. 经典同步问题(Classic Problems of Synchronization)
    • !!Bouded Buffer Problem
    • !!Readers-Writers Problem
    • dining philosophers problem
    • 其他同步问题
      • 1. 使用二进制semaphore实现counting semaphore
      • 理发师问题
  • 六、 管程(Monitor)
    • Semaphore的使用问题
    • monitor的提出
    • Condition Variable
    • monitor模式对dining philosopher问题解法的实现(使用CV)
    • !!使用Semaphore实现monitor
      • 不使用CV的实现方法
      • 使用CV时monitor的实现方法

一、背景

  • 对共享数据的并发访问会导致数据不一致性(数据的处理结果与人规定的既定规则下的结果不同)

例子:在生产者和消费者体系中,二者修改一个count,但却在各自的进程空间进行,但是修改过程中可能会出现这种情况:

二、 临界区(Critical-Section)

上述对count的修改就是critical section

理论上的解决方案要满足(单核状态):

  1. Mutual Exclusion :如果某个进程正在进行它的critical section,那么其他进程不能进行其critical section。
  2. Process:如果没有进程处于critical section,且有进程想要进入critical section,需要选出一个不能被无限期推迟的进程进入critical section
  3. Bounded Waiting :当一个进程需要且已经被授权准入critical section时,它等待其他进程先进入critical section的时间应当是有限的。

另外:

  • 假设每个进程都以非0速度执行
  • 没有进程间相对执行速度相对执行速度的概念

Peterson’s Solution

进程的情况


代码情况:

while (true) {flag[i] = TRUE;turn = j;while ( flag[j] && turn == j);CRITICAL SECTIONflag[i] = FALSE;REMAINDER SECTION
}
// Pj代码完全对称
while (true) {flag[j] = TRUE;turn = i;while ( flag[i] && turn == i);CRITICAL SECTIONflag[j] = FALSE;REMAINDER SECTION
}

简单的形式?


当一个process的remainder section很长,难以结束,另一个就无法进入critical section。

三、 硬件同步机制(Synchronization Hardware)

很多系统提供对critical section code的硬件帮助

  • 使用单处理器时,可以使处理器进入不可中断模式
  • 处理器硬件提供原子性的操作,要么使用TestAndSet,要么使用Swap

TestAndSet Instruction

// 被共享的lock初始化为false// 指令描述
boolean TestAndSet (boolean *target){boolean rv = *target;*target = TRUE;return rv;
}// 使用
while (true) {while ( TestAndSet (&lock )); /* do nothing*/// critical sectionlock = FALSE;// remainder section
}

这种方法不能够满足Bounded waiting,之后的更新后的ppt有可以实现Bounded waitng的TestAndSet方法。

Swap Instruction

不满足Bounded Waiting

// Definition:
void Swap (boolean *a, boolean *b){boolean temp = *a;*a = *b;*b = temp:
}
// Solution:
while (true) {key = TRUE;while ( key == TRUE) Swap (&lock, &key );// critical sectionlock = FALSE;// remainder section
}

四. 信号量(Semaphores)

简单的同步化工具,通过两个原子化的标准操作修改一个integer值 S S S :wait()signal()(一开始也被称为P()V()

wait(S){while(S<=0) /*此处如果不空,则这个进程在忙等待*/;S--;
}
signal(S){S++;
}

显然S不应为负。

Semaphore的版本

  • Counting Semaphore:S的值是不被约束的整数
  • Binary Semaphore:S的值只能是0或1,也被成为mutex locks

简单的使用

上图S的值应当取1

上图中,S的初始值应当为0

Semaphore Implementation

  • 应该确保任意两个进程不能在同一时刻分别对t同一个S运行wait()和signal(),也即wait和signal本身也是critical section。
  • 有忙等待和非忙等待两种方法

busy waiting

(是自旋锁?)

no busy waiting

如果while中的时间不能被忽略,就需要把这些操作放在waiting queue,而不是放在wait操作中。
此时 Semaphore本身应该具有两个字段:

1. 值(以int形式存储)
2. 指向PCB链表(实际上就是waiting queue)的指针

使用2个系统内核和提供的系统调用

  • block
  • wakeup

这样的Semaphore的实现方法:

Implementation of wait:
wait (S){value--;if (value < 0) {// add this process to waiting queueblock(); }
}Implementation of signal:Signal (S){value++;if (value <= 0) {// remove a process P from the waiting queuewakeup(P); }
}

block是让自己睡觉,wakeup是把包括自己在内的 别人叫醒

当使用多处理器并且占用率较低时,busy waiting可以填充CPU时间

Deadlock & Starvation(死锁和饿死)

  • 死锁:所有进程都在等待其他进程执行完成。

    在上图中,P0和P1在都执行完第一句后就会产生死锁

  • starvation:

五. 经典同步问题(Classic Problems of Synchronization)

!!Bouded Buffer Problem

// producer的代码
BoundedBuffer::Producer(){while (true) {// produce an itemwait(empty);wait(mutex);// add the item to the buffersignal(mutex);signal(full);}
}// consumer的代码
BoundedBuffer::Consumer(){while (true) {wait(full);wait(mutex);// remove an item from buffersignal(mutex);signal(empty);// consume the removed item}
}

full和empty确定buffer产生和消费的串行化,而mutex确定从buffer中放入和放出item的critical section的原子性。

但是其实这个mutex对buffer的控制是粗粒度的。如果producer与consumer访问的item在buffer中的位置不相同,这显然不需要采用mutex确保串行化,可以并行访问。只有他们访问同一个item的时候,才需要保护。

!!Readers-Writers Problem

经典问题

  • dataset被一些并发进程共享,readers只读取数据,writers既可以读,又可以写
  • 应当允许多个readers可以一起读一个数据项,但不能允许多个writers(或者writers和readers)一起写(或有写有读)一个数据项。

解决方案:制定一些共享数据:

  • dataset
  • 一个Semaphore:mutex初始化为1,来确保mutual exclusion,其实也是对readcount的保护
  • Semaphore:wrt初始化为1(也是binary的)
  • readcount:integer值,初始化为0
DataBase{BinarySemaphore mutex=1,wrt=1;int readCount = 0;// writer进程的代码void writer(){while (true) {wait(wrt) ;OP_WRITE();// 执行写操作signal(wrt);}}// reader进程的代码void reader(){while (true) {wait(mutex); // 可以看到,上下两段wait(mutex)其实保护了readcount的操作readcount++ ;if (readcount == 1) wait(wrt) ;// 当只有一个reader时,应当把他当做writer对待// 但之后就不能这样做,否则wrt会一直阻塞(因为之后只会signal一次)//此时如果有writer,在这里就会阻塞住,直到没有writer(不论是真的还是假的)signal(mutex);OP_READ();// 执行读操作wait(mutex) ;readcount -- ;if (readcount == 0) signal(wrt) ;signal(mutex) ;}}
}

dining philosophers problem


五个人五根筷子,这是共享数据的情况。只有拿到2根筷子才能吃饭(data)
故:

  • 米饭=>data set
  • Semaphore chopstick[5] init to 1

此时,phil的代码(会产生死锁)

while(true){wait( chopstick[i] );
wait( chopStick[ (i + 1) % 5] );OP_EAT();
signal( chopstick[i] );
signal(chopstick[ (i + 1) % 5] );OP_THINK();
}

在这样的情况下,如果每个phil都拿起左边的筷子,全局就会形成死锁

之后的monitor方法会防止死锁

其他同步问题

1. 使用二进制semaphore实现counting semaphore

struct S{int val;               // init kBinarySemaphore sem;   // init 0,用于对等待S时的排队同步int waitCount;         // init 0,表示在S上等待的进程的数量BinarySemaphore mutex; //init 1,用于保护对waitCount和val的更新
};// wait操作
void wait(struct S s){wait(s.mutex);// 保护val和waitCountif (s.val == 0){// 目前没有空闲,val=0s.waitCount++; // 等待的进程增加signal(s.mutex); // 退出临界区wait(s.sem); // 等待有进程完成了对S的操作,signal掉了sem}else{s.val--;// 还有剩下的val,所以根本不需要waitCountsignal(s.mutex); // 退出临界区}
}void signal(struct S s){wait(s.mutex);// 同样是保护两个数值if(s.waitCount>0){s.waitCount--;signal(s.sem); // 从相当于从等待sem的进程中挑一个执行}else{s.val--;// 这里根本就没有等待的进程,因此也不需要signal(s.sem)}signal(s.mutex);// 最终释放保护信号量
}

总结:

  • 用整数表示计数的方法,用mutex保护操作的整数,但是这个mutex要在整数不使用后马上释放
  • 对整数的判断和修改都需要加mutex锁

理发师问题


解法:

#define n 10
// 其中,costumers不是二进制信号量,因为可能有多个顾客
Semaphore mutex = 1, barber = 1, costumers = 0;
int freeChair = n;/*** 理发师进程 */
void Barber()
{while (1){wait(costumers); // 等待客人,如果没有就睡觉// 客人来到wait(mutex);    // 临界区保护freeChair++;    // barber起身,空出一个座位signal(mutex);  // 临界区结束signal(barber); // 理发师去剪发cutHair();      // 给顾客剪头}
}/*** 顾客进程 */
void Costomers()
{while (1){wait(mutex);// 对freeChair的判断值也可能因为多进程而不准确// 所以用mutex保护if (freeChair > 0){freeChair--;signal(mutex);     // 完成临界区signal(costumers); // 此时顾客已经到来wait(barber);      // 等待理发师剪头haveHairCut();     //顾客被剪头}else{signal(mutex); // 退出临界区,没空位走了}}
}

六、 管程(Monitor)

Semaphore的使用问题

  • 顺序不能错
  • 必须1对1对应

容易出错的原因是Semaphore的运行模式其实是与普通代码一样的。

monitor的提出

在一个时刻,1个condition variable只允许有1个process在monitor中处于active状态,但可以有多个process被挂起(也可以说sleeping)

monitor monitor-name{// shared variable declarationsprocedure P1(…) { …. }…procedure Pn(…) {……}Initialization code( ….) { … }…
}

整体结构:
在这里插入图片描述
其中椭圆内部的每个矩形对应着1个operation。

Condition Variable

CV允许为管程提出个性化的同步方案

这个变量允许的也是两个操作:wait和signal,但语义和Semaphore有区别
condition x;

  • x.wait():调用这个操作的process会被挂起
  • x.signal():从因为x挂起的process中选一个,但如果没有进程在这里等待,就什么也不做

所以condition variable具有一个waiting queue

condition variable的整体结构

从这个结构可以看到,condition variable时monitor的关键,它应当有:

  • 一个指向被挂起进程(也就是PCB)队列的指针
  • 一个用于实现同步的锁和对应的机制(下文使用的就是Semaphore)

monitor模式对dining philosopher问题解法的实现(使用CV)

monitor DP{enum { THINKING; HUNGRY, EATING) state[5] ;condition self[5]; //philosopher i can delay herself when unable to get chopsticksvoid pickup(int i) {state[i] = HUNGRY;test(i);if (state[i] != EATING) self[i].wait();}void putdown(int i) {state[i] = THINKING;// test left and right neighborstest((i + 4) % 5);test((i + 1) % 5);}void test(int i) {if ( (state[(i + 4) % 5] != EATING) &&(state[i] == HUNGRY) &&(state[(i + 1) % 5] != EATING) ) {state[i] = EATING ;self[i].signal() ;}
}initialization_code() {for (int i = 0; i < 5; i++)state[i] = THINKING;}
}

调用时,每个phil只需要如下的调用:

dp.pickup(phil_id);
OP_EAT();
dp.putdown(phil_id);

!!使用Semaphore实现monitor

不使用CV的实现方法

每一个管程都拥有如下的数据结构,它被所有procedure所共有

Semaphore mutex;// init = 1,保护next_count和过程体
Semaphore next;//init 0,把别的进程唤醒,自己等待?
int next_count = 0;// 让位等待的process数,也即在next上等待的进程数

不使用CV时,使用默认的同步方案,这样的方案也是通过Semaphore实现的

procedureF(){wait(mutex);// actual body of Fif(next_count>0) signal(next);// 优先调用让位给别人的processelse signal(mutex);
}

使用CV时monitor的实现方法

对每个condition variable,除了拥有上述3个属于整个管程的变量之外,用于进程同步的字段和方法有:

  • 信号量 x_sem(init 0):
  • 整数值 x_count(init 0):
  • 成员wait操作
  • 成员signal操作

它们的实现如下

struct ConditionVariable{// CV使用的,实现定制化同步的手段BinarySemaphore x_sem = 0;int x_count = 0;PCB wait_queue; // 指向进程的队列void wait(){// 其中的操作应当是原子性的x_count++;if(next_count>0){signal(next);}else{signal(mutex);}wait(x_sem);x_count--;}void signal(){if(x_count>0){next_count++;signal(x_sem);wait(next);next_count--;}}
};

操作系统笔记(6) 进程同步(Process Synchronization)相关推荐

  1. 操作系统——Process Synchronization 进程同步

    目录​​​​​​​ 1. Background 背景 1.1 What is Process Synchronization? 什么是进程同步 1.2 Race condition 竞争条件 1.3 ...

  2. 操作系统概念学习笔记 11 进程同步(一)

    操作系统概念学习笔记 11 进程同步(一) 互相协作的进程之间有共享的数据,于是这里就有一个并发情况下,如何确保有序操作这些数据.维护一致性的问题,即进程同步. 从底层到高级应用,同步机制依次有临界区 ...

  3. 进程同步问题(Process Synchronization)

    CH5 Process Synchronization 文章目录 I. 识别临界区(Race condition) 1. producer–consumer problem用计数器counter会产生 ...

  4. 操作系统笔记(II:从进程同步到文件管理)

    操作系统笔记(II:从进程同步到文件管理) 4.5.2 读者-写者问题 [问题描述] 若干读者.写者,共享文件/数据: 读者:可以同时读数据,不可修改数据. 写者:修改数据,不能同时修改同一份数据,进 ...

  5. 【王道考研】操作系统 笔记 第二章上 进程调度

    本文内容,1.进程和线程 2.进程调度 特此鸣谢王道考研 本文参考王道考研的相关课程 若有侵权请联系,立删 其余笔记链接: [王道考研]操作系统笔记 第一章_才疏学浅743的博客-CSDN博客 [王道 ...

  6. 操作系统笔记——进程管理

    操作系统笔记--进程管理 2. 进程管理 2.1 进程与线程 2.1.1 进程的引入 前趋图 程序的顺序执行 程序的并发执行 2.1.2 进程的定义及描述 进程的定义 进程的特征 进程和程序的关系 进 ...

  7. 操作系统笔记 第二章

    操作系统笔记 第二章 1.有两个程序:A程序按顺序使用CPU10秒.设备甲5秒.CPU5秒.设备乙10秒.CPU10秒:B程序按顺序使用设备甲10秒.CPU 10秒.CPU5秒.设备乙5秒.CPU 5 ...

  8. 操作系统笔记——概述、进程、并发控制

    文章目录 传送门 概述 入门书籍与视频推荐 定义操作系统 操作系统的形成 顺序处理(无操作系统) 批处理系统 单通道批处理系统 多通道批处理系统 分时系统 实时系统 嵌入式系统 操作系统类型总结 操作 ...

  9. 现代操作系统笔记 2.1 进程

    现代操作系统笔记 2.1 进程 前言 从本章开始我们将深入考察操作系统是如何设计和构造的.操作系统中最核心的概念是进程:这是对正在运行程序的一个抽象. 操作系统的其他所有内容都是围绕着进程的概念展开的 ...

  10. 操作系统存储器管理实验报告_献上膝盖!华为工程师抛出一份堪称“举世无双”操作系统笔记...

    写在前面 操作系统在计算机行业中是一门最基础的技术,无论是在开发项目还是在算法岗,我们都是基于计算机上进行的,我们对操作系统的了解体现我们从事计算机相关岗位的资深素质,因此,接下来,这篇文章给大家介绍 ...

最新文章

  1. 【新星计划】MATLAB系统辨识工具箱使用方法
  2. spring mvc DispatcherServlet解读
  3. appium+python自动化51-adb文件导入和导出(pull push)
  4. Oracle闪回技术(Flashback)
  5. python程序设计课程设计二级减速器_二级减速器课程设计
  6. 简述c、c++和java三大语言特性
  7. Unity-ShaderLab 逆向还原《原神》角色卡通渲染思路与实现(保姆级教学)-1
  8. 也许你看了一本假的天龙八部
  9. 【家庭药箱系列】布洛芬小史
  10. FPGA设计之门控时钟
  11. 互联网行业公司岗位与发展方向
  12. 微擎跳过云平台_2018年10月微擎安装之阿里云懒人教程篇
  13. 特斯拉Q4财报:底部反弹70%,为信仰打call
  14. 图标(ico,cur)文件的结构解析
  15. 什么是网站结构,为什么它很重要?
  16. 调用浏览器下载图片 java实现
  17. java 与 汇编_清华大学出版社-图书详情-《汇编语言与计算机体系结构——使用C++和Java》...
  18. 机关值班php代码,机关事业单位值班制度
  19. Word操作之参考文献自动关联和引用
  20. Dubbo 和 Spring Cloud 微服务架构区别(比较笼统 看看就行)

热门文章

  1. 【项目设计】高并发内存池(一)[项目介绍|内存池介绍|定长内存池的实现]
  2. android——做一个电影播放的Demo
  3. Vivado使用技巧(15):DRC设计规则检查
  4. 计算机视觉(相机标定)-2.1 摄像机标定
  5. Nvidia GPU架构 - Cuda Core,SM,SP等等傻傻分不清?
  6. 阿里云centos安装sonar问题记录
  7. Linux:tar命令详解
  8. 电子相册视频制作工具:photo2movie for Mac
  9. Python+selenium 实现自动化163邮箱登录并发送邮件
  10. 最好的云主机评测和比较