本文主要内容:

  • 信号量的实现
  • 利用信号量解决哲学家用餐问题
  • 利用信号量解决生产者消费者问题

一、信号量的实现

1.1 信号量结构

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

value代表当前信号量可以使用的数量,list代表当前信号量上所等待的进程。

1.2 P操作实现

P(semaphore * s)
{
s.value--;
if(s.value < )
{
add current process to s.list;
block();
}
}

如果s.value<0。说明没有资源可用,当前进程加入list(等待进程列表),并且block当前进程。

1.3 V操作实现

V(semaphore * s)
{
s.value++;
if(s.value <= )
{
remove a process A from s.list;
wakeup(A);
}
}

s++代表释放了一个资源,如果s.value++后还是<=0。说明已经有至少一个进程在等待资源,这个时候就从list中拿出几个进程,wakeup这个进程,这样这个进程就可以开始使用这个刚刚被释放的资源了(这个进程不一定马上开始运行,至少是ready状态,什么时候运行取决于CPU的调度算法)。

1.4 忙等待问题

之前的Peterson的方案是通过忙等待来达到进程间的互斥访问的。PV操作其实也是无法避免的,PV操作的前提是不会有两个进程针对一个信号量在同时进行PV操作。这个时候信号量是信号量就是临界区域,如何让P和V操作对于信号量的操作互斥?

操作系统针对这个也是通过忙等待来完成的(一个进程对信号量进行操作的时候,其他进程一直等待)。不过把忙等待最终防止在信号量层面是最大限度的减少了忙等待的时间,因为pv操作的时间是非常快的。

二、利用信号量解决哲学家用餐问题

2.1 问题演示

五个哲学家,如上图所示:

  • 每两个哲学家之间都有一只筷子,总共5只
  • 哲学家都在思考,饿的时候就会拿起两边的筷子去吃饭
  • 只有拿了两支筷子后才能开始吃饭

很明显,如果一个哲学家在想吃饭的时候如果其任何一个邻居在吃饭,他是没有办法吃饭的,筷子不够(要么只有一只筷子或者一只都没有)。

2.2 解决方案

void philosopher(i)
{
while(true)
{
P(chopstick[i]);
P(chopstick[( i + ) % ]);
eat();
V(chopstick[i]);
V(chopstick[( i + ) % ]);
think();
}
}

i代表第i个哲学家(0,1,2,3,4,5)。程序的核心思想就是利用PV操作让哲学家一直等待直到其左右两边的筷子都空闲再开始吃饭,吃完以后再把筷子放回去。

哲学家和筷子的编号

当哲学家0想用餐时,等待0,1筷子,哲学家2想用餐时等待2,3筷子。。

2.3 问题

上面的方案有个缺点:

当所有哲学家同时想用餐时,就会发生死锁,永远等待( starvation):

该问题下一篇博文专门介绍如何解决starvation。

三、利用信号量解决生产者消费者问题

之前的文章引入了生产者和消费者模式,但是该模式有有问题,wakeup有可能会丢失,其实核心问题还是因为对count(buffer容量)的访问没有做进程互斥访问,对buffer的访问没有做互斥访问,通过PV操作可以解决该问题

设置三个信号量:

  • full,代表buffer中item的数量,默认为0
  • empty代表buffer中空闲的数量,默认为buffer的容量n
  • mutex,提供对于buffer的互斥操作,1代表可以访问buffer。0代表不可以访问buffer,初始值为1;
void producer()
{
while(true)
{
produce_item();
P(empty);//空闲容量-1,没有空闲容量,则等待,且进入block列表
P(mutex);//检测buffer是否可以访问
insert_item();
V(mutex);//释放buffer的访问权
V(full);//item数量+1,如果有consumer等待,则唤醒一个consumer
}
} void consumer()
{
while(true)
{
P(full);//item数量-1,如果没有item可以消费,则进入block列表
p(mutex);//检测buffer是否可以访问
remove_item();
V(mutex);//释放buffer访问权限
V(empty);//空闲容量+1,如果有producer等待吗,则唤醒一个producer
consume_item();
}
}

Operating System-进程/线程内部通信-信号量、PV操作的实现和应用(解决哲学家进餐和生产者消费者问题)的更多相关文章

  1. Operating System-进程/线程内部通信-信号量和PV操作

    本文介绍操作系统进程管理的两个核心概念: 信号量 PV操作 一.信号量介绍 1.1 信号量引入 信号量(Semaphore)1965年由Dijkstra引入的.信号量一般由一个值是一个变量,其值有可能 ...

  2. InnoDB: Operating system error number 87 in a file operation. 错误87的解决方法

    InnoDB: Operating system error number 87 in a file operation. 错误87的解决方法 140628  8:10:48 [Note] Plugi ...

  3. Operating System-进程/线程内部通信-管程(Monitor)介绍,实现以及应用

    本文主要内容: 管程(Monitor)介绍 管程实现 管程应用 一.管程(Monitor)介绍 1.1 管程 前一篇文章介绍了信号量以及使用,信号量已经提供了一个方便且高效的进程同步机制,但是信号量有 ...

  4. linux下的信号量PV操作进阶之路

    一.同步和互斥机制 信号量 互斥锁 同步:指多个任务按照约定的先后次序相互配合来完成一件事情. 比如读线程等待写线程写完之后再去读. 二.信号量-P/V操作 P(s)含义: if(信号量>0) ...

  5. java信号量PV操作 解决生产者-消费者问题

    package test1; /** * 该例子演示生产者和消费者的问题(设只有一个缓存空间.一个消费者和一个生产者) * MySystem类定义了缓冲区个数以及信号量 * @author HYY * ...

  6. Linux下IPC中的信号量PV操作

    代码如下所示,两边对照查看程序!(左图为先运行进程 右图为后运行进程)    运行的效果就是:当左边的进程检测到EOF,释放资源V操作之后,右边的进程会迅速的执行对应的printf的操作! 所有代码文 ...

  7. Operating System-进程/线程内部通信-竞争条件(Race Conditions)

    从本文开始介绍进程间的通信,进程间通信遇到的问题以及方式其实和线程之间通信是一致的,所以进程间通信的所有理论知识都可以用在线程上,接下来的系列文章都会以进程之间的通信为模版进行介绍,本文主要内容: 进 ...

  8. Operating System-进程/线程内部通信-临界区(Critical Regions)

    上一篇文章讲述了进程之间的竞争条件:多个进程同时进入一个共享区域,导致了数据的不一致,本文主要介绍如何解决这个问题. 一.临界区介绍 解决这个问题就是阻止多个进程同时进入这个共享区域,换句话说,进程之 ...

  9. Operating System:信号量

    pv原语操作(1)操作系统PV意思:PV操作与信号量的处理相关,P表示通过的意度思,V表示释放的意思.(2)p操作和v操作是不可中断问的程序段,称为原语.如果将信号量看作共享变量,则pv操作为其临界区 ...

随机推荐

  1. Android 平台电容式触摸屏的驱动基本原理

    Android 平台电容式触摸屏的驱动基本原理 Android 平台电容式触摸屏硬件基本原理 Linux 与 Android 的多点触摸协议 Linux输入子系统:事件的编码

  2. linux kernel内存回收机制

    转:http://www.wowotech.net/linux_kenrel/233.html linux kernel内存回收机制 作者:itrocker 发布于:2015-11-12 20:37 ...

  3. JSP笔记02——概述(转)

    不完全翻译,结合谷歌,一定主观性,还可能有误,原始内容地址:https://www.tutorialspoint.com/jsp/jsp_overview.htm 主要内容如下: 什么是JSP? 为什 ...

  4. 对vector,list的操作函数

    向量只能接受同一类型的数据:list可以接受不同的数据. 1.添加元素 vector:> b=c(1,2,3) > b=c(b,"four") #直接在后面添加添加 & ...

  5. 中断下半部tasklet【转】

    本文转载自:http://edsionte.com/techblog/archives/1547 tasklet的实现 tasklet(小任务)机制是中断处理下半部分最常用的一种方法,其使用也是非常简 ...

  6. 通过公钥解密密文思路(256bits RSA)

    256bit RSA公钥安全系数极低,只需要几分钟即可破解密文,本文综合其他文章记录了一次解密256bits RSA加密的密文的过程,仅作为备忘. 1.分解公钥,分解出n与e: 1.1使用openss ...

  7. Go Mysql驱动

    Golang中MYSQL驱动 Mysql库https://github.com/go-sql-driver/mysql Go本身不提供具体数据库驱动,只提供驱动接口和管理. 各个数据库驱动需要第三方实 ...

  8. Web项目java.lang.OutOfMemoryError: PermGen space异常解决

    接手一个新的Web项目,编译运行(Tomcat版本为7),运行的时候报出了java.lang.OutOfMemoryError: PermGen space的异常,搜了一下这样解释:   PermGe ...

  9. eclipse异常关了,tomcat如何关

    eclipse异常关了,tomcat如何关 ? 1.bin文件夹下面有的shutdown.bat.双击即可! 2.在任务管理器里面关闭,看到javaw.exe关闭也行.            

  10. 什么是OOM?如何解决OOM问题!

    1.什么是OOM? 程序申请内存过大,虚拟机无法满足我们,然后自杀了.这个现象通常出现在大图片的APP开发,或者需要用到很多图片的时候.通俗来讲就是我们的APP需要申请一块内存来存放图片的时候,系统认 ...