[No00003C]操作系统Operating Systems进程同步与信号量Processes Synchronization and Semaphore
操作系统Operating Systems进程同步与信号量Processes Synchronization and Semaphore
进程合作:多进程共同完成一个任务

从纸上到实际:生产者− − 消费者实例
共享数据
#define BUFFER_SIZE 10
typedef struct { . . . } item;
item buffer[BUFFER_SIZE];
int in = out = counter = 0; 注意:这些都是用户态程序!
生产者进程
while (true) {
while(counter== BUFFER_SIZE);
buffer[in] = item;
in = (in + 1) % BUFFER_SIZE;
counter++;
}
消费者进程
while (true) {
while(counter== 0);
item = buffer[out];
out = (out + 1) % BUFFER_SIZE;
counter--;
}
找到哪些地方要停,什么时候再走?
需要让"进程走走停停"来保证多进程合作的合理有序
这就是进程同步
生产者进程
while (true) {
while(counter== BUFFER_SIZE); 缓存区满,生产者要停
buffer[in] = item;
in = (in + 1) % BUFFER_SIZE;
counter++;
} 发信号让消费者再走…
消费者进程
while (true) {
while(counter== 0) ; 缓存区空,消费者要停
item = buffer[out];
out = (out + 1) % BUFFER_SIZE;
counter--;
} 发信号让生产者再走…
只发信号还不能解决全部问题

(1) 缓冲区满以后生产者P 1 生产一个item 放入,会sleep信号
(2) 又一个生产者P 2 生产一个item 放入,会sleep
(3) 消费者C 执行1 次循环,counter==BUFFER_SIZE-1 ,发信号给P 1 ,P 1 wakeup
(4) 消费者C 再执行1 次循环,counter==BUFFER_SIZE-2 ,P 2 不能被唤醒
从信号到信号量
不只是等待信号、发信号? 对应睡眠和唤醒!
还应该能记录一些信息
能记录有"2 个进程等待"就可以了…
(1) 缓冲区满, P 1 执行, P 1 sleep ,记录下 个进程等待
(2) P 2 执行, P 2 sleep ,记录下 个进程等待
(3) C 执行 1 次循环,发现 个进程等待, wakeup 1 个
(4) C 再执行 1 次循环,发现 ? 个进 程等待, 再 ?
(5) C 再执行 1 次循环, 怎么办 ? 此时再来 P 3 怎么办 ?
什么是信号量? 记录一些信息( 量) ,并根据这个信息决定睡眠还是唤醒( 信号) 。
信号量开始工作…
初始时 sem = ?
(1) 缓冲区满, P 1 执行, P 1 sleep sem = -1 什么含义?
(2) P 2 执行,P 2 sleep sem = -2
(3) C 执行 1 次循环,wakeup P 1 sem = -1
(4) C 再执行 1 次循环,wakeup P 2 sem = 0
(5) C 再执行 1 次循环, sem = 1 什么含义?
(6) P 3 执行,P 2 继续执行 sem = 0
总结一下:这个整数什么时候-1? 什么时候+1?什么时候睡眠? 什么时候唤醒?
什么是信号量? 信号量的定义…
信号量: 1965 年,由荷兰学者Dijkstra 提出的一种特殊整型变量,量用来记录,信号用来sleep 和wakeup
struct semaphore
{
int value; // 记录资源个数
PCB *queue;// 记录等待在该信号量上的进程
}
P(semaphore s); // 消费资源
V(semaphore s); // 产生资源
P 的名称来源于荷兰语的proberen ,即test
V 的名称也来源于荷兰语verhogen(increment)
P(semaphore s)
{
s.value--;
if(s.value < 0) {
sleep(s.queue); }
}
用信号量解生产者− −消费者问题
int fd = open("buffer.txt");
write(fd, 0, sizeof(int)); // 写in
write(fd, 0, sizeof(int)); // 写out 用文件定义共享缓冲区
semaphore full = 0;
semaphore empty = BUFFER_SIZE; // 信号量的定义和初始化
semaphore mutex = 1;
Producer(item) {
P(empty);
P(mutex);
读入in; 将item 写入到in 的位置上;
V(mutex);
V(full); }
Consumer() {
P(full);
P(mutex);
读入out; 从文件中的out位置读出到item; 打印item;
V(mutex);
V(empty); }
信号量临界区保护Critical Section
共同修改信号量引出的问题
初始情况
empty = -1; //这是什么含义?
Producer(item) {
P(empty);
...}
生产者P 1
register = empty;
register = register - 1;
empty = register;
生产者P 2
register = empty;
register = register - 1;
Empty = register;
一个可能的执行( 调度)
P 1 .register = empty;
P 1 .register = P 1 .register - 1;
P 2 .register = empty;
P 2 .register = P 2 .register - 1;
empty = P 1 .register;
empty = P 2 .register; 最终的empty 等于多少? 对吗?
竞争条件(Race Condition)
竞争条件: 和调度有关的共享数据语义错误
第i次执行
P 1 .register = empty;
P 1 .register = P 1 .register - 1;
P 2 .register = empty;
P 2 .register = P 2 .register - 1;
empty = P 1 .register;
empty = P 2 .register;
第j 次执行
P 1 .register = empty;
P 1 .register = P 1 .register - 1;
empty = P 1 .register;
P 2 .register = empty;
P 2 .register = P 2 .register - 1;
empty = P 2 .register;
错误由多个进程并发操作共享数据引起
错误和调度顺序有关,难于发现和调试
解决竞争条件的直观想法
在写共享变量empty时阻止其他进程也访问empty
仍是那个执行序列
P 1 .register = empty;
P 1 .register = P 1 .register - 1;
P 2 .register = empty;
P 2 .register = P 2 .register - 1;
empty = P 1 .register;
empty = P 2 .register;
生产者P 1
检查并给empty上锁
P 1 .register = empty;
P 1 .register = P 1 .register - 1;
生产者P 2
检查empty 的锁 ? 一段代码一次只允许一个进程进入
生产者P 1
empty = P 1 .register;
给empty 开锁
生产者P 2
检查并给empty 上锁
P 2 .register = empty;
P 2 .register = P 2 .register - 1;
empty = C.register;
给empty
临界区(Critical Section)
临界区: 一次只允许一个进程进入的该进程的那一段代码

一个非常重要的工作: 找出进程中的临界区代码 读写信号量的代码一定是临界区…

临界区代码的保护原则
基本原则:互斥进入: 如果一个进程在临界区中执行,则其他进程不允许进入
这些进程间的约束关系称为 互斥(mutual exclusion)
这保证了是临界区
好的临界区保护原则
有空让进: 若干进程要求进入空闲临界区时,应尽快使一进程进入临界区
有限等待: 从进程发出进入请求到允许进入,不能无限等待
进入临界区Peterson
结合了标记和轮转两种思想

Peterson算法的正确性
满足互斥进入:
如果两个进程都进入,则flag[0]=flag[1]=true ,turn==0==1 ,矛盾!
满足有空让进:
如果进程P 1 不在临界区,则flag[1]=false ,或者turn=0 ,都P 0 能进入!
满足有限等待:
P 0 要求进入,flag[0]=true ;后面的P 1 不可能一直进入,因为P 1 执行一次就会让turn=0

多个进程怎么办? − − 面包店算法
仍然是标记和轮转的结合
如何轮转: 每个进程都获得一个序号,序号最小的进入
如何标记: 进程离开时序号为0 ,不为0 的序号即标记
面包店: 每个进入商店的客户都获得一个号码,号码最小的先得到服务;号码相同时,名字靠前的先服务。

面包店算法的正确性

互斥进入: P i 在临界区内,P k 试图进入,一定有(num[i], i)<(num[k],k) ,P k 循环等待。
有空让进: 如果没有进程在临界区中,最小序号的进程一定能够进入。
有限等待: 离开临界区的进程再次进入一定排在最后(FIFO) ,所以任一个想进入进程至多等n
临界区保护的另一类解法…
再想一下临界区: 只允许一个进程进入, 进入另一个进程意味着什么?
被调度: 另一个进程只有被调度才能执行,才可能进入临界区,如何阻止调度?
- 什么时候不好使?
- 多CPU( 多核)…
问题:为什么不好使?

临界区保护的硬件原子指令法

进程P i
while(TestAndSet(&lock)) ;
临界区
lock = false;
剩余区
想一想: 多CPU 情况好不好使?

[No00003C]操作系统Operating Systems进程同步与信号量Processes Synchronization and Semaphore的更多相关文章
- [No00003D]操作系统Operating Systems信号量的代码实现Coding Semaphore &死锁处理Deadlock
操作系统Operating Systems信号量的代码实现Coding Semaphore &死锁处理Deadlock 可以操刀了—从纸上到实际 从Linux 0.11 那里学点东西… 读磁盘 ...
- [No00003A]操作系统Operating Systems 内核级线程Kernel Threads内核级线程实现Create KernelThreads
开始核心级线程 内核级线程对多核的支持怎么样? 和用户级相比,核心级线程有什么不同? ThreadCreate 是系统调用,内核管理TCB ,内核负责切换线程 如何让切换成型? − − 内核栈,TCB ...
- [No000038]操作系统Operating Systems -CPU
管理CPU ,先要使用CPU… CPU 的工作原理 CPU上电以后发生了什么? 自动的取指 — 执行 CPU 怎么工作? CPU怎么管理? 管理CPU 的最直观方法 设好PC 初值就完事! 看看这样做 ...
- [No000037]操作系统Operating Systems操作系统历史与硬件概况History of OS & Summaries!
培根:读史使人明智 操作系统的简史 (1955-1965) 计算机非常昂贵,上古神机IBM7094 ,造价在250万美元以上 计算机使用原则:只专注于计算 批处理操作系统(Batch system) ...
- [No000036]操作系统Operating Systems系统调用的实现System_Call
实现一个whoami 系统调用 系统调用的直观实现 问题+直观想法… 用户程序调用whoami, 一个字符串"systemcall "放在操作系统中(系统引导时载入) ,取出来打印 ...
- [No000031]操作系统 Operating Systems 之Open the OS!
从打开电源开始… 这神秘的黑色背后发生着什么?… 打开电源,计算机执行的第一句指令什么? 计算模型(图灵机) ⇒ 我们要 关注 指针IP 及其 指向的内容 看看x86 PC (1) 刚开机时CPU 处 ...
- [No000039]操作系统Operating Systems用户级线程User Threads
多进程是操作系统的基本图像 是否可以资源不动而切换指令序列? 进程 = 资源 + 指令执行序列 线程: 保留了并发的优点,避免了进程切换代价 实质就是映射表不变而PC 指针变 多个执行序列+ 一个地址 ...
- Modern Operating Systems(Ⅰ)——2014.12.15
进程 进程模型 进程就是一个正在执行的程序的实例 值得注意的是,若一个程序运行了两遍,则算作两个进程 创建进程 在通用系统中,有四种主要事件导致进程的创建 ①系统的初始化 ②执行了 正在 ...
- Method of address space layout randomization for windows operating systems
A system and method for address space layout randomization ("ASLR") for a Windows operatin ...
随机推荐
- iOS UIAlertController
在Xcode的iOS9.0 SDK中,UIAlertView和UIActionSheet都被UIAlertController取代. 在iOS 9中,UIAlertController在功能上是和UI ...
- 如何收缩超大的SharePoint_Config数据库
前言 在已经运行了2年多的SharePoint服务器上,发现SharePoint_Config的数据库文件越来越大,已经达到90几个GB,收缩可以减小20几个GB,但是一周以后又会恢复到90几个GB大 ...
- SQLLDR 教程
)- 总览 http://blog.csdn.net/dbanote/article/details/9153895 )- 命令行参数 http://blog.csdn.net/dbano ...
- 搭建一个完整的Android工程(一)Dagger2
写在前面 现在越来越多的使用到了开源项目,但是仅限于使用,却不了解,更谈不上深入.也是因为越来越多的开源项目,平时工作中遇到问题也是第一时间寻找对应的开源项目,少了许多独立的思考.现在虽然能很轻松的完 ...
- IntelliJ IDEA 使用总结[zz]
本文转自:http://cowboy-bebop.iteye.com/blog/1035550,仅做稍微整理,转载请注明出处. 1. IDEA内存优化 因机器本身的配置而配置: \IntelliJ I ...
- yii2搭建完美后台并实现rbac权限控制案例教程
作者:白狼 出处:www.manks.top/article/yii2_frame_rbac_template 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连 ...
- 【译】Java中的对象序列化
前言 好久没翻译simple java了,睡前来一篇. 译文链接: http://www.programcreek.com/2014/01/java-serialization/ 什么是对象序列化 在 ...
- goldengate初始化
对丢弃已久的goldengate环境重新配置,使其重新开始跑起来 环境是一个主机上的两个库,都是单机,所以也就没配pump进程了,trail file都是在一个文件夹下的,extract写trail ...
- 按要求编写Java应用程序: (1)编写西游记人物类(XiYouJiRenWu) 其中属性有:身高(height),名字(name),武器(weapon) 方法有:显示名字(printName),显示武器(printWeapon) (2)在主类的main方法中创建二个对象:zhuBaJie,sunWuKong。并分别为他 们的两个属性(name,weapon)赋值,最后分别调用printName,
package com.hanqi.test; public class xiyoujirenwu { private double height;// 身高 private String name; ...
- 我的ElasticSearch集群部署总结--大数据搜索引擎你不得不知
摘要:世上有三类书籍:1.介绍知识,2.阐述理论,3.工具书:世间也存在两类知识:1.技术,2.思想.以下是我在部署ElasticSearch集群时的经验总结,它们大体属于第一类知识“techknow ...