【汤4操作系统】深入理解信号量的使用-三大问题的变体

news2024/11/18 15:24:45

主要从生产者消费者、读写者、哲学家问题中的经典变体进行讲述,均使用伪代码实现

生产者消费者变体

在这里插入图片描述

顾客看作是生产出的产品,理发师看作是消费者,沙发有空位,顾客就进去,沙发有顾客,理发师就去理发

和生产者消费者的区别在于

  • 生产者生产出一个产品后,当缓存没有空位时就会一直等待下去,直到有空位的出现
  • 此问题如果没有空位,用户直接离开,不会加入阻塞队列
semaphore customers = 0,barber = 0;//沙发上的顾客数和正在理发的理发师数目
semaphore mutex = 1;
int count = 0;//沙发上的顾客人数,用来技术
void barber() {
    do {
		wait(customer);//如果沙发有顾客,就起来理发,否则阻塞理发师睡觉
        wait(mutex);//保护count
        count = count - 1;//等待的顾客数减一,开始剪头
        signal(babers); //通知理发师可以开始理发
        signal(mutex);
        haircut();
    }while(TRUE);
}
//没有空位顾客直接离开,所以不需要while循环
void customer() {
    wait(mutex);
    if (count < n) {
        //如果有空椅子则等待的顾客数+1
        count = count + 1;
        signal(customers);
        signal(mutex);
        wait(barbers);//如果理发师忙则等待
    }else {
		signal(mutex);//无椅子离开
    }
}

单缓冲区生产者消费者

有一计算进程和打印进程,它们共享一个单缓冲区,计算进程不断的计算出一个整形结果并将它放入缓冲区,打印进程则负责从单缓冲区中取出每一个结果进行打印

在这里插入图片描述

生产者消费者-单缓冲区

//生产者消费者的完整复杂写法
semaphore mutex = 1;
semaphore full = 0,empty = 1;
int buffer[1];
int in = 0,out = 0;
void calculator() {
    int nextp;
    do {
        calculate into nextp;
       	wait(empty);
        wait(mutex);
        buffer[in] = nextp;
        in = (in + 1) % 2;
        signal(mutex);
        signal(full);
    }while(TRUE);
}

void printer() {
    int nextc;
	do {
        wait(full);
        wait(mutex);
        nextc = buffer[out];
        out = (out + 1) % 2;
        signal(mutex);
        signal(full);
      	print(nextc);
    }while(TRUE);
}

对于单缓冲区而言,可以不需要mutex、buffer数组和in out指针

//生产者消费者的完整复杂写法
semaphore full = 0,empty = 1;
int buffer;
void calculator() {
    int nextp;
    do {
        calculate into nextp;
       	wait(empty);
        buffer = nextp;
        signal(full);
    }while(TRUE);
}

void printer() {
    int nextc;
	do {
        wait(full);
        nextc = buffer;
        signal(full);
      	print(nextc);
    }while(TRUE);
}


多缓冲区生产者消费者变体

有三个进程PA、PB、PC协作解决文件打印问题,PA将文件记录从磁盘读入内存的缓冲区1,每执行一次读入一个记录;PB将缓冲区1的内容复制到缓冲区2中,每执行一次复制一条记录;PC将缓冲区2的内容打印出来,每执行一次打印一条;缓冲区的大小和记录大小一样,请用信号量来保证文件的正确打印。

分析:

该问题中PA是缓冲区1的生产者,PB是缓冲区1的消费者、缓冲区2的生产者,PC是缓冲区2的消费者

该问题为多缓冲区多生产者消费者的变体

因为缓冲区大小为1,故不需要互斥访问量

semaphore full1 = 0,full2 = 0;
semaphore empty1 = 1,empty2 = 1;
item buff1;
item buff2;
void PA() {
    item read1;
    do {
		//从磁盘读入read1;
        wait(empty1);
        buff1 = read1;
        signal(full1);
    }while(true);
}
void PB() {
    item tmp;
    do {
        wait(full1);
        tmp = buff1;//取出缓冲区1的数据
        signal(empty1);
        wait(empty2);
        buff2 = tmp;//存入缓冲区2
        signal(full2);
    }while(true);
}
void PC() {
    item print;
    do {
        wait(full2);
        print = buff2;//取出数据
        signal(empty2);
        print(print);//打印
    }
}

生产者消费者变形

进程A1、A2、…An1通过m个缓冲区向进程B1、B2…Bn2不断地发送消息。发送和接收工作遵循如下规则:

  1. 每个发送进程一次发送一个消息,写入一个缓冲区,缓冲区大小与消息长度相同
  2. 对每个消息,B1、…Bn2都需各自接收一次,读入自己的数据区内
  3. m个缓冲区都满的时候,发送进程等待,没有可读的信息时,接收进程等待

提取信息:

发送进程只发送一次,接收进程取n2次,假设缓冲区长度为n2

设置信号量

mutex=1用来实现对缓冲区的互斥访问

empty[i] (i=1,…n2),初值为m,每个empty[i]对应缓冲池第i格中的所有空闲缓冲区

full[i] (i=1…n2) 初值为0,对应缓冲区第i格中装有消息的缓冲区。

提供整形变量in指示将消息放入哪个缓冲区

out[j] (j=1…n2)用来指示Bj从哪个缓冲区中取消息

Ai() {//i = 1...n1
    int k;
    while (1) {
        for (k = 1;k <= n2;k++) wait(empty[k]);//申请大小为n2的空闲分区
        wait(mutex);
    	把Ai的消息放入第in个缓冲区中
        in = (in + 1) % m;
        signal(mutex);
        for (k = 1;k <= n2;k++) signal(full[k]);
    } 
}

Bi() {
    while (1) {
        wait(full[j]);
        wait(mutex);
        从第out[j]个缓冲区的第j格中取出消息
       	out[j] = (out[j] + 1) % m;
        signal(mutex);
        signal(empty[j]);
        把数据写到消息区
    }
}

生产多个产品的生产者

桌上有个能盛的下五个水果的空盘子,爸爸不停向盘中放入苹果或橘子,儿子不停的从盘中取出橘子,女儿不停的从盘中取出苹果。规定三人不能同时往盘中取放水果,用信号量实现三个循环进程之间的同步

分析:

典型的生产者消费者问题,爸爸为能生产两个产品的生产者,缓冲区大小为5,需要使用mutex来互斥访问

semaphore mutex = 1,orange = 0,apple = 0,empty = 5;
void Father() {
 	while (1) {
        wait(empty);
        wait(mutex);
        //将水果放入盘中
        signal(mutex);
        if (放的橘子) {
            signal(orange);
        }else{
            signal(apple);
        }
    }
}

void Son() {
    while (1) {
        wait(orange);
        wait(mutex);
        取出橘子
        signal(mutex);
        signal(empty);
        吃了
    }
}

void Daughter() {
    while (1) {
        wait(apple);
        wait(mutex);
        取出苹果
        signal(mutex);
        signal(empty);
        吃了
    }
}

多个生产者+限制

设有两个生产者进程A、B和一个销售者进程C,它们共享一个无限大的仓库,生产者每次循环生成一个产品,然后入库供销售者销售;销售者每次循环从仓库中取出一个产品进行销售。如果不允许同时入库,也不允许边入库边出库;而且要求生产A产品和B产品的件数满足以下的关系:-n<=A的件数-B的件数<=m,其中n,m为正整数,但是对仓库中的A、B无限制,请用信号量机制写出A、B、C的工作流程

分析:

缓冲池:无限大的仓库,临界资源,使用mutex互斥

AB差值的约束,若A生产1份差值加一,B生产一份差值减一,则用信号量来控制这个差值:

SAB【sub A B】= m【允许A生产的产品数量】,SBA【sub B A】 = n【允许B生产的产品数量】

仓库无限大,但是C的销售需要仓库中的产品数量参考,设信号量S = 0代表仓库中初始产品个数

semaphore mutex = 1,SAB = m,SBA = n,S = 0;
A () {
    while (1) {
        //生产产品 
        wait(SAB);//生产一个A
        wait(mutex);
        signal(SBA);//B能生产的个数+1
        //放入仓库
        signal(S);
        signal(mutex);
    }
}
B () {
	while (1) {
        //生产产品
        wait(SBA);
        wait(mutex);
        signal(SAB);
        //放入仓库
        signal(S);
        signal(mutex);
    }
}

C() {
    while (1) {
		wait(S);
        wait(mutex);
        //取出仓库产品
        signal(mutex);
        //销售
    }
}

读写者变体

请出一种写者优先的读者写者问题的算法描述

在读者优先的算法上,增添一个初值为1的信号量S,使得当至少一个写者准备访问共享对象时,它可使后续的读者进程等待写完成;初值为0的writecount对写者进行计数;初值为1的互斥信号量wmutex,实现多个写着对writecount的互斥访问

reader() {
    while (1) {
        wait(S);
        wait(rmutex);
        if (readcount == 0) wait(mutex);
        readcount++;
        signal(rmutex);
        signal(S);
        //读
        wait(rmutex);
        readcount--;
        if (readcount == 0) signal(mutex);
        signal(rmutex);
    }
}

writer() {
    while (1) {
		wait(wmutex);
        if (writecount == 0) wait(rmutex);
        writecount++;
        signal(wmutex);
    	wait(mutex);
        //写
        signal(mutex);
        wait(wmutex);
        writecount--;
        if (writecount == 0) signal(S);
        signal(wmutex);
   	}
}

请用信号量解决以下的过独木桥问题:同一方向的行人可连续过桥,当某一方向有人过桥时,另一方向的行人必须等待,当某一方向无人过桥时,另一方向行人可以过桥

独木桥问题是读者写者问题的变形,相当于两种不同的读者,相同读者可以同时读,不同读者必须互斥

semaphore bridge = 1;//用来实现不同方向行人对桥的互斥
int countA,countB = 0;//AB两个方向过桥的人数
semaphore mutexA,mutexB = 1;//用来实现对countA、countB的互斥共享
void  PA() {
    wait(mutexA);
    if (countA == 0) wait(bridge);
    countA++;
    signal(mutexA);
    过桥
    wait(mutexA);
    countA--;
    if (countA == 0) signal(bridge);
    signal(mutexA);
}
//B的代码和A一致,都是读者格式代码

哲学家变体

有一间酒吧里有3个音乐爱好者队列,第一队的音乐爱好者只有随身听,第二队的音乐爱好者只有磁带,第三队的只有电池,而要听音乐必须三个俱全。酒吧老板一次出售三种中的任意两种。当一名音乐爱好者得到三种并听完一首乐曲后,98老板才能再次出手三种的两种,一直循环进行下去。

三种临界资源随身听、磁带、电池。

记磁带电池为S1,随身听电池S2,随身听磁带S3【两种物品必须被同一个音乐爱好者取走,将两个看作一个组合起来的临界资源】

一次最多只有一个完整的组合,听完后才能再次出售商品,记为music

semaphore S1 = S2 = S3 = 1,music = 0;
void fan1() {
	wait(S1);
    //购买磁带电池
    //听音乐
    signal(music)
}
void fan2() {
    wait(S2);
    //购买随身听电池
    //听音乐
    signal(music);
}
//fan3同理
void boss() {
    while (1) {
        //提供任意两种产品售卖
        if (卖的是磁带电池) {
            signal(S1);
        }else if (卖的是随身听电池){
            signal(S2);
        }else{
            Signal(S3);
        }
        wait(music);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/654391.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis客户端 - Jdies快速入门

原文首更地址&#xff0c;阅读效果更佳&#xff01; Redis客户端 - Jdies快速入门 | CoderMast编程桅杆Redis客户端 - Jdies快速入门 简介 Jedis is a Java client for Redis designed for performance and ease of use. Jedis是Redis 的 Java 客户端&#xff0c;专为性能和易…

Python中使用matplotlib绘制各类图表示例

折线图 折线图是一种用于表示数据随时间、变量或其他连续性变化的趋势的图表。通过在横轴上放置时间或如此类似的连续变量&#xff0c;可以在纵轴上放置数据点的值&#xff0c;从而捕捉到数据随时间发生的变化。折线图可以用于比较不同变量的趋势&#xff0c;轻松地发现不同的…

不写代码如果解决Jmeter跨线程组取参数值问题?

目录 前言 定义属性法 文件转接法 总结&#xff1a; 前言 如果你工作中已经在用jmeter做接口测试&#xff0c;或性能测试了&#xff0c;你可能会遇到一个麻烦。 那就是jmeter的变量值不能跨线程组传递。 看&#xff0c;官方就已经给出了解释&#xff1a; 这个不是jmeter的…

机器学习——识别足球和橄榄球

一、选题的背景 橄榄球起源于足球&#xff0c;二者即相似又有所区别。计算机技术发展至今&#xff0c;AI技术也有了极大的进步&#xff0c;通过机器学习不断的训练&#xff0c;AI对于足球和橄榄球的识别能力可以帮助人们对足球和橄榄球的分辨。机器学习是一种智能技术&#xff…

虚拟机使用docker安装MySql出现的问题,Navicat连不上MySql

文章目录 一、问题引入 二、问题分析 三、问题解决 ​四、总结 一、问题引入 今天是学习谷粒商城的第一天&#xff0c;既然是第一天&#xff0c;肯定就是先对项目先有个基本的了解&#xff0c;比如是项目所用到的技术栈&#xff0c;项目整体的架构等&#xff0c;还对分布…

操作系统闲谈09——内存管理算法

操作系统闲谈09——内存管理算法 Buddy伙伴系统 假设存在一段连续的页框&#xff0c;阴影部分表示已经被使用的页框&#xff0c;现在需要申请一个连续的5个页框。这个时候&#xff0c;在这段内存上不能找到连续的5个空闲的页框&#xff0c;就会去另一段内存上去寻找5个连续的页…

华为OD机试真题B卷 JavaScript 实现【乱序整数序列两数之和绝对值最小】,附详细解题思路

一、题目描述 给定一个随机的整数&#xff08;可能存在正整数和负整数&#xff09;数组 nums&#xff0c;请你在该数组中找出两个数&#xff0c;其和的绝对值(|nums[x]nums[y]|)为最小值&#xff0c;并返回这个两个数&#xff08;按从小到大返回&#xff09;以及绝对值。 每种…

Android 行业就业难! 我是否该负重前行~

不知从何时开始&#xff0c;互联网市场岗位开始以收缩趋势进行发展&#xff0c;使得不少互联网行业的从业者面临者工作难找的难题&#xff0c;对于我们开发人群来说很不友好。 以前可以靠着跳槽实现涨薪梦&#xff0c;而如今是能不动就不动&#xff0c;能稳住是最好。 为什么这…

Docker——安装MySQL

一、安装并拉取MySQL镜像 先把docker启动起来 systemctl restart docker systemctl status docker 安装MySQL docker search mysql拉取镜像&#xff0c; 如果拉取不成功或者显示超时&#xff0c;可以去配置加速镜像源。 二、查看本地镜像并启动MySQL 但是光有镜像没有把镜像…

Redis面试之数据类型及底层原理

废话不多说直接上类型 string&#xff08;字符串&#xff09; hash&#xff08;哈希&#xff09; list&#xff08;列表&#xff09; set&#xff08;集合&#xff09; zset&#xff08;有序集合&#xff09; stream&#xff08;流&#xff09; geospatial&#xff08;地…

CRM软件有哪些?这9款值得推荐

业内有一句流传已久的话&#xff1a;你的左手不知道你的右手在做什么。同一个企业内部&#xff0c;不同部门之间往往存在信息不同步&#xff0c;数据不对称的情况&#xff0c;比如销售和营销部门关于某个市场活动所带来的效果产生分歧。CRM软件的存在就可以解决这类问题。 在正…

实验4 Cache性能分析【计算机系统结构】

实验4 Cache性能分析【计算机系统结构】 前言推荐实验四 Cache性能分析1 实验目的2 实验平台3 实验内容和步骤3.1 Cache容量对不命中率的影响3.2 相联度对不命中率的影响3.3 Cache块大小对不命中率的影响3.4 替换算法对不命中率的影响 4 实验总结与心得5 请思考 最后 前言 202…

8年测试工程师分享,我是怎么开展性能测试的(基础篇)

第一节 测试的一般步骤 性能测试的工作是基于系统功能已经完备或者已经趋于完备之上的&#xff0c;在功能还不够完备的情况下没有多大的意义&#xff08;后期功能完善上会对系统的性能有影响&#xff0c;过早进入性能测试会出现测试结果不准确、浪费测试资源&#xff09;&…

足不出户怎么在家赚钱,暑假在家别闲着,给自己赚点生活费吧

在当今快节奏的现代生活中&#xff0c;人们面临着越来越大的竞争压力。为了过上舒适的生活、提前退休、创业或增加收入&#xff0c;许多人都希望能够在家中赚钱。那么&#xff0c;在家里如何可以找到赚钱的项目呢&#xff1f;本文将为您详细介绍一些方法。 一、在家工作有很多好…

《计算之魂》读书笔记——第2章,从递推到递归

我们人类的固有思维方式常常是出于直观的&#xff0c;由近及远、从少到多&#xff0c;这样的思维方式让我们很容易理解具体的事物&#xff0c;却也限制了我们的抽象思维&#xff0c;所以当我们理解远离我们生活经验的事物时&#xff0c;就容易出现障碍。我们人类这种自底向上、…

调用万维易源实现天气预测

作者介绍 房庚晨&#xff0c;男&#xff0c;西安工程大学电子信息学院&#xff0c;22级研究生 研究方向&#xff1a;机器视觉与人工智能 电子邮件&#xff1a;1292475736qq.com 王泽宇&#xff0c;男&#xff0c;西安工程大学电子信息学院&#xff0c;2022级研究生&#xff0…

easyui03(tree后台工作)

一.数据库脚本 create table TB_MODULE ( id NUMBER not null, pid NUMBER not null, text VARCHAR2(150) not null, iconcls VARCHAR2(100) not null, url VARCHAR2(100), sort NUMBER not null ) insert into TB_MODULE (id, pid, text, icon…

Android音视频开发实战01-环境搭建

一,FFmpeg介绍 FFmpeg 是一款流行的开源多媒体处理工具&#xff0c;它可以用于转换、编辑、录制和流式传输音视频文件。FFmpeg 具有广泛的应用场景&#xff0c;包括视频编解码、格式转换、裁剪、合并、滤镜等等。官网:https://ffmpeg.org/ FFmpeg 支持各种常见的音视频格式&a…

设置论文中的图、表的题注(小记)

参考b站&#xff1a;毕业论文图表如何自动编号/word图表自动编号/图表编号自动更新 其中&#xff0c;更新图表序号 视频使用ctrlp进入打印再退出&#xff0c;也可以使用altf9进行更新 设置论文中的图、表的题注 step1:设置章节1.1 章节设置字体样式&#xff0c;选择标题11.2 章…

中国人民大学与加拿大女王大学金融硕士项目就像一束光,照亮你的春夏秋冬

不要因为看到别人发光&#xff0c;就默认自己的暗淡。每个人都有自己的闪光时刻&#xff0c;或早或晚。只要努力奋进&#xff0c;你也会拥有。针对金融行业计划在职的人员来说&#xff0c;中国人民大学与加拿大女王大学金融硕士项目就像一束光&#xff0c;照亮了我们的春夏秋冬…