PV操作-同步与互斥

news2024/9/21 12:43:53

浅记学习PV操作的部分题目。

消费者与生产者

单生产者与单消费者


理解PV操作可以从消费者与生产者之间的关系入手。

一个生产者与消费者的情况


消费者想要获取一份商品,需要检查市场中该商品是否有余量:

  • 如果剩余商品足够,则获取该商品。
  • 如果剩余商品不足,则等待生产者生产该商品,生产后再获取。

消费者获取到商品之后应通知生产者:市场刚刚被消费了一份,出现了空位,你要继续生产。

生产者想要生产一份商品,需要检查市场中是否有空间允许加入新的商品:

  • 如果市场没有饱和,存在相关需求,则生产一份商品加入市场。
  • 如果市场已经饱和,没有位置插入商品,则等待市场出现空缺,有位置后再生产。

生产者生产出商品之后应通知消费者:刚刚制造了商品,市场出现了余量,你可以来买了。

尝试用代码表示

empty表示生产者当前有多少缓冲区可用。

  • 1:有一个缓冲区可用。
  • 0:没有缓冲区可用了。
  • -1:没有缓冲区可用,同时有一个生产者在排队等待生产。

full表示消费者有多少商品可以使用。

  • 1:有一个商品可用。
  • 0:没有商品可用。
  • -1:没有商品可用,同时有一个消费者在排队等待上架货物。
//生产者进程
while(1){
    //P(empty)
    empty--;//尝试生产一份商品
    if(empty<0)//没地方了,堵塞等待
        sleep(s1.queue);//有地方再生产
    full++;//生产完了,增加一份
    //V(full)
    if(full<=0){//有消费者还在等待
        wake_up(s2.queue);//唤醒消费者
    }
}
//消费者进程
while(1){
    //P(full)
    full--;//尝试消耗一份商品
    if(full<0)//商品不够了,堵塞等待
        sleep(s2.queue);//等着来货
    //V(empty)
    empty++;//有货,消耗一份
    if(empty<=0)//有生产者在堵塞
        wake_up(s1.queue);//唤醒生产者
}

PV操作底层

struct semaphore{
    //记录资源的个数
    int value;
    //记录等待在该信号上的进程
    PCB* queue;
}
P(semaphore S){
    s.value--;
    if(s.value<0)
        sleep(s.queue);
}
V(semaphore S){
    s.value++;
    if(s.value<=0)
        wake_up(s.queue);
}

P操作就是信号量-1,如果有余量,允许操作,则继续操作,否则进入等待状态。
V操作就是信号量+1,如果有余量,允许操作,则唤醒一个等待中的进程。

代码表示

如果市场只允许在同一时间执行加入或取出一个操作,那么需要在向市场中添加、取出货物时进行PV操作。
并且初始值为1,表示只有这一个资源,当被一个进程占用时,其他进程将无法访问。

producter(){
    while(True){
        produce an item;
        P(empty);
        P(mutex);
        add item to buffer;
        V(mutex);
        V(full);
    }
}

consumer(){
    while(True){
        P(full);
        P(mutex);
        remove an item from buffer;
        V(mutex);
        V(empty);
        consume the item;
    }
}

多消费者与多生产者

dad(){
    while(True){
        prepare an apple;//准备一个苹果
        P(plate);//看看盘子有没有位置
        put an apple;//有的话把苹果放进去
        V(apple);//苹果就绪了
    }
}
daughter(){
    while(True){
        P(apple);//看看此时有没有苹果
        take an apple;//有的话取出苹果
        V(plate);//腾出盘子
        eat the apple;//吃掉苹果
    }
}
mom(){
    while(True){
        prepare an orange;//准备一个橙子
        P(plate);//看看盘子有没有位置
        put an orange;//把橙子放进去
        V(orange);//橙子就绪了
    }
}
son(){
    while(True){
        P(orange);//看看此时有没有橙子
        take an orange;//有的话取出橙子
        V(plate);//腾出盘子
        eat the orange;//吃掉橙子
    }
}

读者与写者

有以下需求:

  • 允许多个读者同时对文件进行读操作。
  • 只允许一个写者往文件写信息。
  • 任一写者在完成写操作之前不允许其他读者或写者工作。
  • 写者执行写操作之前,应让已有的读者和写者全部退出。

读优先

下面的伪代码存在问题:如果一直有读者请求访问,那么写者可能永远无法获取到资源。

//定义信号量
int count=0;
semaphore mutex=1;
semaphore rw=1;
//读者进程
reader(){
    while (True)
    {
        P(mutex);//请求操作临界资源
        if(count==0)//我是第一个来的
            P(rw);//占用资源
        count++;//访问人数++
        V(mutex);//释放临界资源
        reading...
        P(mutex);//请求操作临界资源
        count--;//我要走了,访问人数--
        if(count==0)//我是最后一个读者
            V(rw);//释放资源
        V(mutex);//释放临界资源
    }
}
writer(){
    while (True)
    {
        P(rw);//请求写操作
        writing...
        V(rw);//释放临界资源
    }
}

写优先

通过一个新的信号量w

  • 请求写的时候会申请这部分临界资源,堵塞之后的读写请求。
  • 请求读操作时会申请这部分临界资源,并在成功申请后释放这部分资源。
    • 对于当前进程,成功申请则表明没有写进程在访问。读进程申请这部分资源只是为了检测有没有写进程,因此在申请后需要及时释放。
    • 对于后续的读进程,由于之前的读进程在申请到临界资源后会立即释放,因此信号量与申请前相同。不会堵塞后续的读进程。
    • 对于后续的写进程,由于之前的读进程在申请到临界资源后会立即释放,因此能够成功申请。由于写操作在写完之后才释放资源,所以写操作执行时会堵塞后续的读写请求,以避免出现“写者可能永远无法获取到资源”的情况。
// 定义信号量
int count = 0;
semaphore mutex = 1;
semaphore rw = 1;
semaphore w = 1;
// 读者进程
reader()
{
    while (True)
    {
        P(w);
        P(mutex);       // 请求操作临界资源
        if (count == 0) // 我是第一个来的
            P(rw);      // 占用资源
        count++;        // 访问人数++
        V(mutex);       // 释放临界资源
        V(w);
        reading... P(mutex); // 请求操作临界资源
        count--;             // 我要走了,访问人数--
        if (count == 0)      // 我是最后一个读者
            V(rw);           // 释放资源
        V(mutex);            // 释放临界资源
    }
}
writer()
{
    while (True)
    {
        P(w);
        P(rw);            // 请求写操作
        writing... V(rw); // 释放临界资源
        V(w);
    }
}

吸烟者问题

互斥隐藏在同步中

semaphore offer1=0,offer2=0,offer3=0,finish=0;
int num=0;
Smoker1(){
    while(True){
        P(offer1);
        抽烟...
        V(finish);
    }
}
Smoker2(){
    while(True){
        P(offer2);
        抽烟...
        V(finish);
    }
}
Smoker3(){
    while(True){
        P(offer3);
        抽烟...
        V(finish);
    }
}
Supplier(){
    while(True){
        //放材料
        P(finish);
        num++;
        num=num%3;
        if(num==0)
            V(offer1);
        else if(num==1)
            V(offer2);
        else
            V(offer3); 
    }
}

哲学家吃饭问题

需要信号量mutex,在申请chopstick之前申请信号量mutex,拿取左右筷子视为一次原子操作。
以避免“所有哲学家同时拿到了左筷子,等待右筷子,导致都没有两双筷子”的情况发生。

semaphore chopstick[5]={1,1,1,1,1};
semaphore mutex=1;
Philosopher(){
    do{
        P(mutex);
        P(chopstick[i]);
        P(chopstick[(i+1)%5]);
        V(mutex);
        eat...
        V(chopstick[i]);
        V(chopstick[(i+1)%5]);
        think...
    }while(True);
}

营业员与顾客

与前面几道不同,这里营业员和顾客方法内,各自P和V的数量是不相等的。
到底是P是V,用不用PV操作,要看实际的需求:

  • P可以理解为:申请、占用,本质是-1。
  • V可以理解为:释放、唤醒,本质是+1。
semaphore seats = 10;     // 有十个座位的资源信号量
semaphore mutex = 1;      // 取号机互斥的信号量
semaphore haveCustem = 0; // 顾客与营业员同步,无顾客时营业员休息

process 营业员
{
    while (True)
    {
        P(haveCustem); // 有没有顾客需要服务
        叫号...
        为顾客服务...
    }
}
process 顾客
{
    P(seats);                   // 是否有座位
    P(mutex);                   // 申请使用取号机
    从取号机上取号... 
    V(mutex);				 	// 取号完毕
    V(haveCustem);              // 通知营业员有新顾客到来
    等待营业员叫号... V(seats); // 离开座位
}

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

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

相关文章

Vue.js和TypeScript:如何完美结合

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

msvcp120.dll怎么修复?msvcp120.dll丢失的解决方法

在当今这个信息化的时代&#xff0c;电脑已经成为我们生活和工作中不可或缺的一部分。然而&#xff0c;随着电脑技术的不断发展&#xff0c;我们也会遇到各种各样的问题。其中&#xff0c;msvcp120.dll丢失是一个常见的问题。一、msvcp120.dll 文件介绍 1 msvcp120.dll 文件的定…

windows7远程连接linux可视化界面——vnc使用教程(华为云服务器实测通过)

** CentOS系统 ** 首先&#xff0c;我们将安装VNC服务系统所需的库文件&#xff0c;这里我们将使用系统自带的yum包管理器进行安装。 yum install xorg-x11-xauth xterm libXi libXp libXtst libXtst-devel libXext libXext-devel -y接下来&#xff0c;我们将安装xvfb服务&…

采用Linux 6.5 内核的Manjaro Linux 23.0正式上线

据了解&#xff0c;当前Manjaro Linux 23.0已正式发布&#xff0c;代号“Uranos”&#xff0c;该版本采用的是Linux 6.5 内核。 依据相关资料可知&#xff0c;Manjaro Linux是一款“快速、用户友好、面向桌面、基于 Arch Linux”的发行版&#xff0c;并且还拥有诸多的显著特征…

python爬虫大作业爬取豆豆影评

python爬虫大作业爬取豆豆影评 一、系统介绍二、效果展示三、其他系统实现四、获取源码 一、系统介绍 1)数据描述 数据来源&#xff1a;豆豆最受欢迎的影评 数据获取&#xff1a;豆豆最受欢迎的影评并将获取的这些信息&#xff08;评论链接、电影名、电影详细地址、评论标题以…

基于YOLOv8模型的深海鱼目标检测系统(PyTorch+Pyside6+YOLOv8模型)

摘要&#xff1a;基于YOLOv8模型和BDD数据集的自动驾驶目标检测系统可用于日常生活与海洋中检测与定位深海鱼目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的目标检测&#xff0c;另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统采用YOLOv…

高德地图实现-微信小程序地图导航

效果图&#xff1a; 一、准备阶段 1、在高德开放平台注册成为开发者2、申请开发者密钥&#xff08;key&#xff09;。3、下载并解压高德地图微信小程序SDK 高德开放平台&#xff1a; 注册账号(https://lbs.amap.com/)) 申请小程序应用的 key 应用管理(https://console.ama…

【unocss】apply聚合语法,unocss配置

前言 最近在使用unocss时&#xff0c;我感觉原子化CSS把这些类名堆在一个标签里&#xff0c;实在谈不上精致美观&#xff0c;那我们有没有办法将这些样式类名搬到style里呢&#xff1f;有的&#xff0c;unocss、tailwindCSS都给出了一种语法 #apply 操作方法 这个不可以直接…

狮子鱼社区团购小程序v18.1独立全开源版+小程序前端

狮子鱼社区团购商城系统小程序V18.1独立开源版&#xff0c;该系统本身就非常完善也没更新的必要&#xff0c;此系统拿来即用非常方便&#xff0c;同一版一样人类小徐特别优化很多细节首页美化了下&#xff0c;如小程序端授权窗口美化了下&#xff0c;该版本用户授权接口正常。功…

数据分享|R语言逻辑回归、线性判别分析LDA、GAM、MARS、KNN、QDA、决策树、随机森林、SVM分类葡萄酒交叉验证ROC...

全文链接:http://tecdat.cn/?p27384 在本文中&#xff0c;数据包含有关葡萄牙“Vinho Verde”葡萄酒的信息&#xff08;点击文末“阅读原文”获取完整代码数据&#xff09;。 介绍 该数据集&#xff08;查看文末了解数据获取方式&#xff09;有1599个观测值和12个变量&#xf…

ubuntu中如何用docker下载华为opengauss数据库(超简单)

ubuntu中如何下载华为opengauss数据库 前言一、安装docker1.方法一&#xff1a;2.方法二 二、拉取openguass镜像三、创建容器四、连接数据库 ,切换到omm用户 &#xff0c;用gsql连接到数据库五.最后用DateGrip远程连接测试(1&#xff09;选择数据源(2&#xff09;查看虚拟机ip地…

ITIL 4指导、计划和改进—评估和计划

第3章 评估和计划 当规划改进或其他倡议时&#xff0c;了解当前状态至关重要。这使组织能够&#xff1a; ● 比较当前状态与期望的未来状态&#xff1b; ● 找出两个状态之间的差距&#xff1b; ● 开发符合逻辑的计划以弥补这些差距。 3.1 评估的基础 评估用于测量、分析…

Slim-neck by GSConv:自动驾驶车辆检测器架构的更好设计范式(文末附代码)

Slim-neck by GSConv:自动驾驶车辆检测器架构的更好设计范式 摘要引言相关工作本文方法GSConv的优势在于轻量级检测器&#xff0c;这些检测器通过添加DSC层和Shuffle来增加非线形表达能力。但是&#xff0c;如果GSConv在模型的所有阶段都使用&#xff0c;模型的网络层会变得更深…

Django系列:Django开发环境配置与第一个Django项目

Django系列 Django开发环境配置与第一个Django项目 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/1328…

三维模型3DTile格式轻量化压缩处理的数据质量提升方法分析

三维模型3DTile格式轻量化压缩处理的数据质量提升方法分析 在处理三维模型3DTile格式的轻量化压缩时&#xff0c;如何在减少数据量的同时&#xff0c;保证或提升数据质量是一大挑战。以下为一些提升数据质量的方法分析&#xff1a; 改进几何简化算法&#xff1a;在进行几何简化…

精品SpringCloud的B2C模式在线学习网微服务分布式

《[含文档PPT源码等]精品基于SpringCloud实现的B2C模式在线学习网站-微服务-分布式》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程等 软件开发环境及开发工具&#xff1a; 开发语言&#xff1a;Java 框架&#xff1a;springcloud JDK版本&#xf…

基于matlab中点放炮各类地震波时距曲线程序

完整程序&#xff1a; clear all dx50;x-500:dx:500;%炮检距 h100;V11500; theta25*pi/180; V2V1/sin(theta); t1sqrt(x.*x4*h*h)/V1;%反射波时距曲线 t2abs(x)./V1;%直达波时距曲线 %折射波时距曲线 xm2*h*tan(theta);%求盲区 k1; for i1:length(x) if x(i)<-xm …

Python提取JSON数据中的键值对并保存为.csv文件

本文介绍基于Python&#xff0c;读取JSON文件数据&#xff0c;并将JSON文件中指定的键值对数据转换为.csv格式文件的方法。 在之前的文章Python提取JSON文件中的指定数据并保存在CSV或Excel表格文件内&#xff08;https://blog.csdn.net/zhebushibiaoshifu/article/details/132…

Mac电脑安装Zulu Open JDK 8 使用 spring-kafka 消费不到Kafka Partition中的消息

一、现象描述 使用Mac电脑本地启动spring-kakfa消费不到Kafka的消息&#xff0c;监控消费组的消息偏移量发现存在Lag的消息&#xff0c;但是本地客户端就是拉取不到&#xff0c;通过部署到公司k8s容器上消息却能正常消费&#xff01; 本地启动的服务消费组监控 公司k8s容器服…

安防监控视频系统EasyCVR+AI算法智能分析网关助力智慧校园建设

学生是祖国的未来&#xff0c;学校就是培育学生的地方。随着校园信息化建设的不断发展&#xff0c;信息服务在校园管理中的作用也越来越强。在保障学生安全与校园高效管理上&#xff0c;人工智能做出了极大贡献&#xff0c;旭帆科技安防监控系统/视频汇聚/云存储/AI智能视频分析…