408OS_PV操作大题总结

news/2024/9/24 19:27:10

咸鱼今年压了读者写者问题,前几年没考过。

死锁的四个条件是:

  • 禁止抢占(no preemption):系统资源不能被强制从一个线程中退出。
  • 持有和等待(hold and wait):一个线程在等待时持有并发资源。持有并发资源并还等待其它资源,也就是吃着碗里的望着锅里的。
  • 互斥(mutual exclusion):资源只能同时分配给一个线程,无法多个线程共享。
  • 循环等待(circular waiting):一系列线程互相持有其他进程所需要的资源。必须有一个循环依赖的关系。

死锁只有在四个条件同时满足时发生,预防死锁必须至少破坏其中一项。

生产者-消费者问题

特点:进程与进程之间是“ 生产资源一消耗资源的关系
六步做题

  1. 有几类进程?——每类进程对应一个函数
  2. 在每个函数内部,用自己的语言描述进程动作(只做一次-不加while 或者 不断重复-加while(1)
  3. 分析每一动作之前,是否需要P()操作
    P()必有V(),每写一个P(),就安排一个V()
  4. 所有 PV 写完后,才去定义信号量,定义完再确认每个信号量的初值是多少
  5. 注意连续出现多个P操作是否会导致死锁
  6. 检查题意

例题:
img

graph TD A[生产者A] --> F1[工厂F1] B[生产者B] --> F2[工厂F2] F1 --> C[组装工人] F2 --> C

分析:

  1. 几类进程?—— 2类:生产车间和装配车间

  2. 描述每类动作
    见下图绿蓝紫的框架部分。

  3. 安排PV操作
    分析每一动作之前,是否需要P()一个东西。
    以车间1为例:

  • 生产A零件之前不需要等待任何资源,所以生产A零件之前不需要P();
  • 把A零件放入F1之前需要确保F1有空位,因此需要P(empty_F1)
  • 什么地方会V(empty_F1)?——装配工人从F1取走
  • F2同理
  • 从F1取A,A可能不够,所以在此之前需要P(A),V(A)在把A放入F1之后
  • 从F2取B,同理
  • 组装不需要PV操作
  1. 定义信号量
Semaphore mutex1=1; //互斥访问货架F1
Semaphore mutex2=1; //互斥访问货架F2
Semaphore empty1=10; //货架F1上有几个空位
Semaphore full1=0; //货架F1上有几个A零件
Semaphore empty2=10; //货架F2上有几个空位
Semaphore full2=0; //货架F2上有几个B零件
  1. 注意连续出现多个P操作是否会发生死锁
  2. 检查题意

img

单纯的同步问题——前驱后继问题

可以按照生产者消费者问题的六步做题法来做。

哲学家进餐问题

一张圆桌上坐着5名哲学家,每两个哲学家之间的桌上摆一根筷子,桌子的中间是一碗米饭。哲学家们倾注毕生的精力用于思考和进餐,哲学家在思考时,并不影响他人。只有当哲学家饥饿时,才试图拿起左、右两根筷子(一根一根地拿起)。如果筷子己在他人手上,则需等待。饥饿的哲学家只有同时拿起两根筷子才可以开始进餐,当进餐完毕后,放下筷子继续思考。

img
特点: 只有一类进程,但需要占用多个资源才能运行
三种思路:

  1. 限制申请资源的顺序。如:规定单号哲学家先取左筷子,双号先取右筷子。(不建议使用)
  2. 限制并发进程数。如:规定同一时间只能有一个哲学家就餐(禁止并行)。(也不建议使用)
  3. 让进程一口气取得所有资源,再开始运行。如:哲学家只有能够取得两个筷子的时候才会就餐。
// 代码来自https://www.cnblogs.com/lordtianqiyi/p/17677155.html
semaphore mutex = 1;    // 互斥拿筷子
semaphore chopstick[5] = {1,1,1,1,1};
void philosopher(int i){while(true){/*当哲学家饥饿时,总是先拿左边的筷子,再拿右边的筷子*/P(mutex)P(chopstick[i]);P(chopstick[(i+1)%5]);V(mutex)// 吃饭/*当哲学家进餐完成后,总是先放下左边的筷子,再放下右边的筷子*/V(chopstick[i]);V(chopstick[(i+1)%5]);}
}

为防止同时拿到左筷子而死锁的情况,这里在拿筷子时加了一个互斥信号量mutex。拿筷子时互斥,这样就不会出现同时拿到左筷子的情况。但是效率较低。
更好的做法是把筷子变成int型变量

// 万能模板
semaphore mutex = 1;    // 互斥拿筷子
int chopstick[5] = {1,1,1,1,1};
void philosopher(int i){while(true)// 当哲学家左右筷子不全在时,跳转回while,循环{P(lock);if (chopstick[i] && chopstick[(i+1)%5] ){// 条件是所有资源都足够-- chopstick[i];-- chopstick[(i+1)%5];// 所有资源int值--V(mutex);break;}else{V(mutex); // 跳回while}// 吃饭 P(lock); // 一口气归还所有资源++ chopstick[i];++ chopstick[(i+1)%5]; V(lock);}
}

例题:2019真题
img
分析:

  1. 姑且认为只有一类进程——哲学家

philosopher(){while(1){get left chopstick;get right chopstick;get bowl;eat;}
}

理发师问题

是服务-被服务的关系
img
分析:

  • 有几类进程?—— 2类:理发师和顾客
  • 没有顾客时理发师可不可以睡觉?可以的话则阻塞;不可以(2011.45)则循环忙等
  • 座位是否有限?座位不够顾客跑路,座位够顾客等待
  • 如何用代码表示取号和叫号
int waiting = 0; // 已取号但还没被服务的人数
semaphore mutex_wait = 1; // 互斥访问waiting
semaphore Service = 0; // 服务信号量
semaphore customer = 0; // 顾客信号量,用于理发师睡觉// 顾客
customer_i(){while(1){get number;P(mutex_wait);waiting++;V(mutex_wait);// 被叫号之后才能被服务// V(customer); // 叫醒理发师等待被叫号;P(Service); // 被叫号对应一次服务// cut hair;}
}// 理发师
server_j(){while(1){ // 如果不睡觉,理发师需要循环工作P(mutex_wait);if(waiting>0){ // 有人在等待call number;waiting--;V(mutex_wait);V(Service);// cut hair;}else{V(mutex_wait); // P(customer) //睡觉}}
}

读者写者问题

读者和写着两组并发进程共享一个文件,要求:多个读者可以同时读文件;只允许一个写者写文件;任一写者在完成写操作之前不允许其他人工作;写者写之前,应该让已有的读写者都退出。
分析:本质就是连续多个同类进程访问同一个临界资源的问题
2类进程:读者和写者。
其中有互斥关系的是:写者之间、写者与读者之间。
代码参考https://www.cnblogs.com/Mount256/p/16804609.html
这位老哥写得挺好的,我就没必要再改了,就加了点注释。

读优先

int count = 0; // 读者数量
semaphore busy = 1; // “读文件”和“写文件”的互斥锁
semaphore mutex = 1; // 变量 count 的互斥锁Reader(){ // 读者进程while(1){P(mutex); // 给count上锁count++; if (count == 1){ // 有人读时加锁,后面人继续读不用再加锁了P(busy); // 有读者时因互斥关系不能写}V(mutex);// 读文件; P(mutex);count--; if (count == 0){ // 没有读者时去锁V(busy);}V(mutex);}
}Writer(){ // 写者进程while(1){P(busy);// 写文件;V(busy);}
}

读优先缺点是读进程会抢占资源到站写者饥饿。

读写公平

int count = 0;
semaphore queue = 1; // 实现“读写公平”的互斥锁,可以视为一个队列
semaphore busy = 1; // “读文件”和“写文件”的互斥锁
semaphore mutex = 1; // 变量 count 的互斥锁Reader(){ // 读者进程while(1){P(queue); // 在无写进程请求时不需要进入队列P(mutex); // 该互斥量实际上是多余的,上面语句已经兼有互斥功能count++; if (count == 1){ P(busy);}V(mutex); // 该互斥量实际上是多余的,下面语句已经兼有互斥功能V(queue); // 恢复对共享文件的访问,不然其他读者没法读了// 读文件; P(mutex);count--; if (count == 0){ V(busy);}V(mutex);}
}Writer(){ // 写者进程while(1){P(queue); // 在无其他写进程请求时不需要进入队列P(busy);// 写文件;V(busy);V(queue); // 恢复对共享文件的访问}
}

这样子有一个写者排入队列就会把后面的读者堵住,后面的读者形成不了抢占。
顺序为:之前的读者-写者-后来的读者

写优先

int ReaderCount = 0; // 读者数量
int WriterCount = 0; // 写者数量
semaphore Read = 1; // “读文件”的互斥锁
semaphore Write = 1; // “写文件”的互斥锁
semaphore ReaderMutex = 1; // 变量 ReaderCount 的互斥锁
semaphore WriterMutex = 1; // 变量 WriterCount 的互斥锁Reader(){ // 读者进程while(1){P(Read); // 每个读进程都需要对 Read 加锁P(ReaderMutex); // 对 ReadCount 的互斥,实际上,上条语句已经兼有此功能,可以去掉ReaderCount++; if (ReaderCount == 1){ // 如果是第一个读进程P(Write); // 则对写者上锁}V(ReaderMutex); // 对 ReadCount 的互斥,实际上,下条语句已经兼有此功能,可以去掉V(Read); // Read 解锁读文件; P(ReaderMutex); // 对 ReadCount 的互斥ReaderCount--; if (ReaderCount == 0){ // 如果是最后一个读进程V(Write); // 则对写者解锁}V(ReaderMutex); // 对 ReadCount 的互斥}
}Writer(){ // 写者进程while(1){P(WriterMutex); // 对 WriterCount 的互斥WriterCount++; if (WriterCount == 1){ // 如果是第一个写进程P(Read); // 则对读者上锁}V(WriterMutex); // 对 WriterCount 的互斥P(Write); // Write 加锁写文件; V(Write); // Write 解锁P(WriterMutex); // 对 WriterCount 的互斥WriterCount--; if (WriterCount == 0){ // 如果是最后一个写进程V(Read); // 则对读者解锁}V(WriterMutex); // 对 WriterCount 的互斥}
}

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

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

相关文章

2024.9.24 思维导图与PDF

哈哈哈终于有我也用过的东西啦~Xmind一款打工人用了都说好的软件(#.#) 【知识小课堂1】不同款式的思维导图:【知识小课堂2】PDF转换器! 1、PDF(便携式文档格式),这种文件格式与操作系统平台无关 —— PDF文件不管是在Windows还是别的操作系统中都是通用的。 2、这一特点使它…

如何设计一个伪无埋点的框架?

主要基于无埋点的缺点,来设计一个伪无埋点的框架,使得业务既可以拥有无埋点的特性,又能满足业务的数据分析需求本文同步发布于公众号:移动开发那些事如何设计一个伪无埋点的框架 在前面的文章:Android无埋点技术概览 中提到传统的无埋点有几大缺点:埋点字段有限,没有办法…

吴恩达机器学习课程 笔记4 分类 逻辑回归

逻辑回归 机器学习中的逻辑回归(Logistic Regression)是一种广泛使用的分类算法,尽管它的名字中包含“回归”这个词,但实际上它主要用于解决分类问题,特别是二分类问题。逻辑回归模型可以用来预测某一类事件发生的概率,例如预测用户是否会点击广告、病人是否患有某种疾病…

设计模式之中介模式(三分钟学会一个设计模式)

中介模式(Mediator)又称之为调停模式。mediator [ˈmiːdieɪtə(r)] n. 调停者;斡旋者;解决纷争的人(或机构); 本意就是解决纠纷的中间人它是面向对象六大原则中最少知道原则的一个典型应用。(关于面向对象六大原则,可看前文:https://www.cnblogs.com/jilodream/p/535351…

Large Vision Model

LVM https://yutongbai.com/lvm.html https://zhuanlan.zhihu.com/p/671423679Large Vision Model(简称LVM)是一种纯粹基于视觉数据进行训练和推理的大型模型,其特点在于无需涉及任何自然语言输入或输出。该模型的提出源自一篇由UC Berkeley的三位计算机视觉专家联合撰写的论…

2024 天池云原生编程挑战赛决赛名单出炉,冠军来自中山大学、昆仑数智战队

9 月 20 日,2024 天池云原生编程挑战赛决赛答辩完美落幕,12 支进入决赛的团队用精彩的答辩,为历时 3 个月的大赛画下了圆满的句号。其中,来自中山大学的陈泓仰以及来自昆仑数智的冉旭欣、沈鑫糠、武鹏鹏,以出色的方案、创新的优化思路、过硬的技术实力分获赛道一和赛道二的…

1panle搭建的maxkb增加本地向量模型

首先下载模型,比如m3e-large,并上传到/opt/maxkb/model/local_embedding/ 目录,没有就创建 目录如下:然后修改1panel的容器信息,点击右边的编辑:在下方的挂在目录处点击添加:在两个框都输入: /opt/maxkb/model/local_embedding 然后,确认保存,再重启容器 重启成功后…

WinForm右键菜单的快键键设置

原文链接:https://blog.csdn.net/zhourongxiang1/article/details/138176092 Form中有一个富文本框控件,在里面右键鼠标,弹出下拉菜单。快捷键的效果则是按下alt+p,触发按下属性事件。 1.从工具箱添加RichTextBox2.然后添加ContextMenuStrip 3.选择RichTextBox的ContextMenu…