信号量基础和两个经典例子

信号量基础和两个经典例子

信号量(semaphore)

用于进程中传递信号的一个整数值。

三个操作:

1、一个信号量可以初始化为非负值

2、semWait操作可以使信号量减1,若信号量的值为负,则执行semWait的进程被阻塞。否则进程继续执行。

3、semSignal操作使信号量加1。若信号量的值小于等于0,则被semWait操作阻塞的进程讲被接触阻塞。

ps: semWait对应P原语,semSignal对应V原语。

信号量以及PV原语的C语言定义如下

struct semaphore
{
	int count;
	queueType queue;
}

void semWait(semaphore s)
{
	s.count--;
	if(s.count<0)
	{
		//把当前的进程插入到队列当中
		//阻塞当前的进程
	}
}

void semSignal(semaphore s)
{
	s.count++;
	if(s.count<=0)
	{
		//把进程P从队列当中移除
		//把进程P插入到就绪队列中等待运行。
	}
}

使用信号量进行互斥的方法

假如S=1,那么运行了semWait(s)之后,s的值就为0,进程进入了临界区;如果S的值为负的,则进程被阻塞

semaphore s=1;
void  p(int i)
{
	while(true)
	{
		semWait(s);
		//临界区
		semSignal(s);
		//其他部分
	}
}

生产者/消费者问题

以下是无限缓冲区的解决方法,有限缓冲区再设置一个信号量e=缓冲区大小即可。

semaphore n=0,s=1;
void producer()
{
	while(true)
	{
		produce();//生产产品
		semWait(s);//s=0使用缓冲区的时候使用S信号量禁止消费者进入
		append();//往缓冲区加入数据
		semSignal(s);//s=1允许消费者进入
		semSignal(n);//n=1表示缓冲区数据量为1,允许消费者进入
	}
}

void consumer()
{
	while(true)
	{
		semWait(n);//n>=1时,往缓冲区取数据
		semWait(s);//s=0使用缓冲区的时候使用S信号量禁止生产者进入
		take();//取走产品
		semSignal(s);//s=1允许生产者进入
		consume();//消费产品
	}
}

读者/写者问题

读者优先

int readcount;//readcount用于记录读进程的数目
semaphore x=1,wsem=1;//wsem为Write Semaphore,用于实施互斥
void reader()
{
	//信号量x用于确保readcount被正确的更新
	while(true)
	{
		semWait(x);
		readcount++;
		if(readcount==1)
			semWait(wsem);//读的时候不允许写操作
		semSignal(x);
		READUNIT();//读操作
		semWait(x);
		readcount--;
		if(readcount==0)
			semSignal(wsem);
		semSignal(x);
	}
}

void writer()
{
	while(true)
	{
		semWait(wsem);
		WRITEUNIT();//写操作
		semSignal(wsem);
	}
}

写者优先

int readcount;//readcount用于记录读进程的数目
int writecount;//控制resm的设置
semaphore x=1,wsem=1,resm=1;//wsem为Write Semaphore,用于实施互斥
void reader()
{
	//信号量x用于确保readcount被正确的更新
	while(true)
	{
		semWait(z);//只允许一个读进程在resm上排队,其他读进程在等待resm之前,在信号量z上排队.z初始化?
			semWait(resm);//信号量resm:当至少有一个写进程访问数据区时,禁止所有读进程
				semWait(x);
				readcount++;
				if(readcount==1)
					semWait(wsem);//读的时候不允许写操作
				semSignal(x);
			semSignal(resm);
		semSignal(z);

		READUNIT();//读操作

		semWait(x);
		readcount--;
		if(readcount==0)
			semSignal(wsem);
		semSignal(x);
	}
}

void writer()
{
	while(true)
	{
		semWait(y);//信号量y用于确保writecount被正确的更新
		writecount++;
		if(writecount==1)
			semWait(resm);
		semSignal(y);

		semWait(wsem);
		WRITEUNIT();//写操作
		semSignal(wsem);

		semWait(y);
		writecount--;
		if(writecount==0)
			semSignal(resm);
		semSignal(y);
	}
}
时间: 2024-12-25 19:44:50

信号量基础和两个经典例子的相关文章

小猪的数据结构辅助教程——2.6 经典例子:魔术师发牌问题和拉丁方阵问题

小猪的数据结构辅助教程--2.6 经典例子:魔术师发牌问题和拉丁方阵问题 标签(空格分隔): 数据结构 本节引言: 本节继续带来的是循环链表的两个经典例子,分别是魔术师发牌问题和拉丁方阵问题! 1.魔术师发牌问题 问题描述: 魔术师利用一副牌中的13张黑桃牌,预先将他们排好后叠放在一起,牌面朝下.对观众说:"我不看牌,只数数就可以猜到每张牌是什么,我大声数数,你们听,不信?现场演示."魔术师将牌堆最上面的哪张排数为1,把他翻过来正好是黑桃A,将黑桃A从牌堆抽出放在桌子上,第二次数1.2

linux Posix 信号量 三 (经典例子)

本文将阐述一下信号量的作用及经典例子,当中包括“<越狱>寄信”,“家庭吃水果”,“五子棋”,“接力赛跑”,“读者写者”,“四方恋爱”等 首先,讲 semWait操作(P操作)和semSignal操作(V操作)的一些基本原则.(接下来同意称为P,V操作) 1. P操作,s - -,if(s<0)阻塞自己 2. V操作,s++,if(s<=0)唤醒一个其他进程 3. P,V操作时原语(通俗讲,就是执行PV操作时时不能被打打断的) 4. P,V操作总是成对出现的.P:资源申请/分配:V操

第七篇:两个经典的文件IO程序示例

前言 本文分析两个经典的C++文件IO程序,提炼出其中文件IO的基本套路,留待日后查阅. 程序功能 程序一打印用户指定的所有文本文件,程序二向用户指定的所有文本文件中写入数据. 程序一代码及其注释 1 #include <iostream> 2 #include <fstream> // 使用文件处理对象记着要包含这个头文件 3 #include <string> 4 #include <vector> 5 6 using namespace std; 7

小猪的数据结构辅助教程——2.5 经典例子:约瑟夫问题的解决

小猪的数据结构辅助教程--2.5 经典例子:约瑟夫问题的解决 标签(空格分隔): 数据结构 约瑟夫问题的解析 关于问题的故事背景就不提了,我们直接说这个问题的内容吧: 一堆人,围成一个圈,然后规定一个数N,然后依次报数,当报数到N,这个人自杀,其他人鼓掌!啪啪啪, 接着又从1开始报数,报到N又自杀-以此类推,直到死剩最后一个人,那么游戏结束! 这就是问题,而我们用计算机模拟的话,用户输入:N(参与人数),M(第几个人死),结果返回最后一个人! 类似的问题有跳海问题,猴子选王等,下面我们就以N =

什么是 “动态规划” , 用两个经典问题举例

1.什么是动态规划? 看了很多题解,一般解决者开始就说用DP来解,然后写了嵌套的for循环,不是很容易看懂,但是确实解出来了,我们这次来看下到底什么是动态规划?它有什么特点呢?容我抄一段话: 动态规划(Dynamic programming,DP),通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法.通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量: 一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同一个子问题解之时直接查表. 这种做法在重复

javascript经典例子

javascript经典例子  一.验证类 1.数字验证内 1.1 整数 1.2 大于0的整数 (用于传来的ID的验证) 1.3 负整数的验证 1.4 整数不能大于iMax 1.5 整数不能小于iMin 2.时间类 2.1 短时间,形如 (13:04:06) 2.2 短日期,形如 (2003-12-05) 2.3 长时间,形如 (2003-12-05 13:04:06) 2.4 只有年和月.形如(2003-05,或者2003-5) 2.5 只有小时和分钟,形如(12:03) 3.表单类 3.1 

Conquer-Divide的经典例子之Strassen算法解决大型矩阵的相乘

在通过汉诺塔问题理解递归的精髓中我讲解了怎么把一个复杂的问题一步步recursively划分了成简单显而易见的小问题.其实这个解决问题的思路就是算法中常用的divide and conquer, 这篇日志通过解决矩阵的乘法,来了解另外一个基本divide and conque思想的strassen算法.矩阵A乘以B等于X, 则Xij = 注意左乘右乘的区别,AB 与BA是不同的.如果r = 1, 直接就是两个数的相乘.如果r = 2, 例如X = [ 1, 2;   3, 4];Y = [ 2,

递归的几个经典例子

注意:构造方法不可递归,否则是无限创建对象; 递归的几个经典例子: 1.HannoiTower 1 import java.util.Scanner; 2 public class HanoiTower{ 3 //level代表盘子个数;三个char类型代表柱子 4 public static void moveDish(int level, char from, char inter, char to){ 5 if(level == 1){ 6 System.out.println("从&qu

用两个小例子来解释单例模式中的“双重锁定”

学习单例模式时,好多人都不太理解双重锁定.学完后突然想到一个很有趣的例子. 单例模式结构图: 代码: Singleton类 class Singleton { private static Singleton instance; private static readonly object syncRoot = new object(); //程序运行时创建一个静态只读的进程辅助对象 private Singleton() { } //用private修饰构造方法,防止外界利用new创建此类实例