操作系统学习笔记-2.3哲学家和管程问题
哲学家问题
问题描述
假设有五位哲学家围坐在一张圆桌旁,每位哲学家面前放有一盘意大利面,他们各自间隔放置一根叉子。哲学家的行为分为“思考”和“进餐”两种状态。为了进餐,哲学家需要同时拿起左手边和右手边的两根叉子。用餐结束后,他会放下叉子并继续思考。
问题的挑战
在此问题中,哲学家会面临以下资源竞争和同步问题:
-
死锁:如果每个哲学家都拿起了左边的叉子并等待右边的叉子(同理右边情况),将会导致死锁,因为每个人都在等待别人释放叉子。
-
饥饿:即使没有死锁,某些哲学家可能长时间无法获得两把叉子,从而导致饥饿问题。
-
并发控制:我们希望尽可能让哲学家同时进餐,最大化资源利用率,避免资源被长时间锁住。

解决方案
哲学家问题的解决方案通常围绕以下思路展开,以确保哲学家不会陷入死锁或饥饿:
1. 奇偶编号的解决方法
让奇数编号的哲学家先拿左边的叉子,再拿右边的叉子;偶数编号的哲学家则相反。这样可以避免所有哲学家都同时拿起左边的叉子,从而减小死锁风险。
2. 服务员(或“门童”)机制(同时拿两只筷子)
引入一个“服务员”进程,只有在两个相邻的叉子都空闲时才允许哲学家进餐。服务员控制哲学家的进餐顺序,保证不会导致所有哲学家都拿到一只叉子后陷入等待。

3. 限制进餐人数
限制同时进餐的哲学家人数,比如限制为4人。这样一定有一名哲学家不会持有叉子,从而打破等待环,防止死锁的发生。
4. 信号量控制
使用信号量 semaphore 控制哲学家行为,可以设置一个信号量数组 forks,每个叉子与信号量相关联。当哲学家需要用餐时,尝试获取两侧的信号量,成功则用餐,否则等待。
管程
管程(Monitor)是一种高级的同步机制,提供了一种结构化的方式来管理并发环境下的共享资源。它是一种进程同步的抽象,可以看作是一种对象,封装了资源、共享数据以及对这些数据进行操作的过程,同时也提供了一个互斥访问的环境。

1. 管程的概念
管程是一种面向对象的同步原语,用于协调多个线程或进程对共享资源的访问。它包含以下关键部分:
-
共享资源:资源是所有线程需要访问的共享数据,如缓冲区、文件、变量等。
-
互斥访问:管程通过内置的互斥机制,确保在任何时刻只有一个线程能访问其内的数据,从而避免数据竞争和不一致性。
-
条件变量:管程使用条件变量来管理线程的等待和通知机制,允许线程在某种条件未满足时释放资源并进入等待状态。当条件满足时,被通知的线程可以重新获取资源继续执行。
2. 管程的结构

管程通常包含以下内容:
-
锁:管程内部有一个隐含的锁来保证互斥访问。线程在进入管程时需要获取锁,退出时会释放锁。
-
共享变量:管程中定义的共享变量在多个线程间共享,这些变量只能通过管程内部的方法来访问。
-
条件变量(Condition Variables):用于管理线程等待的条件。条件变量通常提供了
wait()和signal()方法:wait():如果条件未满足,调用线程会释放锁并进入等待状态。signal():当条件满足时,唤醒一个等待的线程,让它重新尝试进入临界区。
3. 管程的工作原理
管程的典型工作流程如下:
-
互斥进入:当线程进入管程时,获得管程的锁,确保只有一个线程可以访问管程的共享数据。
-
条件等待:如果条件不满足,线程会通过条件变量的
wait()操作进入等待状态,同时释放锁。其他线程可以获得锁并尝试进入管程。 -
条件通知:当某个条件满足时,线程可以通过条件变量的
signal()操作来通知等待的线程。 -
互斥退出:线程执行完操作后,释放锁,让其他线程可以进入管程。
4. 管程的典型应用
引入管程的目的无非就是要更方便地实现进程互斥和同步。
- 需要在管程中定义共享数据(如生产者消费者问题的缓冲区)
- 需要在管程中定义用于访问这些共享数据的“入口”—其实就是一些函数(如生产者消费者问题中,可以定义一个函数用于将产品放入缓冲区,再定义一个函数用于从缓冲区取出产品)
- 只有通过这些特定的“入口”才能访问共享数据
- 管程中有很多“入口”,但是每次只能开放其中一个“入口”,并且只能让一个进程或线程进入(如生产者消费者问题中,各进程需要互斥地访问共享缓冲区。管程的这种特性即可保证个时间段内最多只会有一个进程在访问缓冲区。注意:这种互斥特性是由编译器负责实现的程序员不用关心)
- 可在管程中设置条件变量及等待/唤醒操作以解决同步问题。可以让一个进程或线程在条件变量万上等待(此时,该进程应先释放管程的使用权,也就是让出“入口”);可以通过唤醒操作将等待在条件变量上的进程或线程唤醒。
- 程序员可以用某种特殊的语法定义一个管程(比如: monitor ProducerConsumer …end monitor;)之后其他程序员就可以使用这个管程提供的特定“入口”很方便地使用实现进程同步/互斥了。采用了封装思想
5. 管程的优缺点
-
优点:
- 简化同步代码的设计:管程将同步逻辑封装在对象内部,提高了代码的模块化和可读性。
- 保证了互斥访问,避免了死锁、资源竞争等问题。
-
缺点:
- 实现相对复杂:尤其在需要处理多个条件变量的场景下,代码复杂度增加。
- 扩展性有限:管程一般用于单机多线程的同步,分布式系统中应用有限。
2.3 其它杂七杂八知识点
临界区(Critical Section)指的是程序中多个线程可能同时访问的共享资源或共享代码片段。临界资源是多个线程或进程共享并且需要互斥访问的资源。
互斥信号量通常在未被占用时为1,被占用时为0。当信号量值为0时,其他线程将会被阻塞,直到该信号量重新释放(恢复到1)
可重入编码(Reentrant Code)是一种可以安全地在多个线程或多个进程中并发执行而不出现冲突的编码方式。可重入代码在执行时不会依赖全局或静态变量,也不保留静态状态,因此避免了多线程环境中的数据竞争。
mutex 的初值为1,表示允许一个进程进入临界区,当有一个进程进入临界区且没有进程等待进入时,mutex 减1,变为0。|mutex|为等待进入的进程数。
相关文章:
操作系统学习笔记-2.3哲学家和管程问题
哲学家问题 问题描述 假设有五位哲学家围坐在一张圆桌旁,每位哲学家面前放有一盘意大利面,他们各自间隔放置一根叉子。哲学家的行为分为“思考”和“进餐”两种状态。为了进餐,哲学家需要同时拿起左手边和右手边的两根叉子。用餐结束后&…...
2023年信息安全工程师摸底测试卷
目录 1.密码算法 2.等级保护 3.密码学 4.安全评估 5.网络安全控制技术 6.恶意代码 7.身份认证 8.资产管理 9.密码分类 10.被动攻击 11.商用密码服务编辑 12.超文本传输协议 13.数字水印技术 14.信息系统安全设计 15.重放攻击 16.信息资产保护 17.身份认证 …...
ReactOS系统中平衡二叉树。给定地址超导其所属区块MmFindRegion()
系列文章目录 PMM_REGION NTAPI MmFindRegion( PVOID BaseAddress, PLIST_ENTRY RegionListHead, PVOID Address, PVOID* RegionBaseAddress ); 宏函数 //给定地址找到其中所属区块 #define CONTAINING_RECORD(address,type,field) ((type FAR *\(PCHAR)(address)-(PCHAR)(&…...
基于TESSY的单元测试与分类树方法深入解析
在现代软件开发中,单元测试是确保软件质量和可靠性的关键步骤之一。特别是对于嵌入式软件,由于其应用环境的特殊性和高安全性要求,单元测试显得尤为重要。本文将基于《TESSY 用户手册》的内容,详细介绍如何使用TESSY 进行单元测试,并深入探讨分类树方法(Classification T…...
整理了一些大模型的课程,非常详细,大模型零基础入门到精通,收藏我这一篇就够了
目前有多个科普类的大模型课程,这些课程涵盖了从基础理论到实际应用的各个方面。以下是一些主要的科普类大模型课程:复旦大学“大模型开发与赋能”专题讲习班:由复旦大学计算机学院邱锡鹏教授带来的《大模型科普讲解》课程,通过深…...
区块链国赛题目--食品溯源(模块三)
区块链国赛题目–食品溯源(模块三) 任务 3-1:区块链应用前端功能开发 1.请基于前端系统的开发模板,在登录组件 login.js、组件管理文件components.js 中添加对应的逻辑代码,实现对前端的角色选择功能,并测试功 能完整性,示例页面如下: 具体要求如下: (1)有明…...
【Searxng】Searxng docker 安装
SearXNG将用户的查询请求分发至多个支持的搜索引擎,并收集返回的结果进行汇总处理。在这个过程中,它通过内置的过滤器功能屏蔽广告和其他不相关内容,确保搜索结果的纯净度。 一键部署 docker run \--name searxng \-p ????:8080 \-v ~/s…...
Java Lock/AQS ReentrantLock 源码
前言 相关系列 《Java & Lock & 目录》(持续更新)《Java & AQS & 目录》(持续更新)《Java & Lock/AQS & ReentrantLock & 源码》(学习过程/多有漏误/仅作参考/不再更新)《Jav…...
魔法伤害--是谁偷走了我的0
起因:需要迁移数据进行数据更新,使用pandasorcal进行数据处理以及库迁移 首先把数据导出为xls格式数据文件,使用python import pandas as pdnew_obj pd.read_excel(ne,dtype{DAY: str, MONTH: str}) 原有导出数据格式为: 使用…...
【ArcGIS Pro实操第4期】绘制三维地图
【ArcGIS Pro实操第4期】绘制三维地图 ArcGIS Pro绘制三维地图-以DEM高程为例参考 如何使用ArcGIS Pro将栅格数据用三维的形式进行表达?在ArcGIS里可以使用ArcScene来实现,ArcGIS Pro实现原理跟ArcScene一致。由于Esri未来将不再对ArcGIS更新,…...
Vuestic 整理使用
简单示例 1. 条件渲染 2. 列表渲染 3. 组件插槽 4. 插值语法 5. 前后端路由的区别(还是转一下,可以减少代码量)SFC 构建 … … Okay,可以干活了,通顺 数据表的操作更加简化了 数据类别通过后端路由区别,但是还得由前端路由转一下 简单了许多呀,上脚手…...
学习伊圣雨老师的 epoll 编程
(1)书里提出了疑问,epoll 函数的工作方式,区分为水平触发与边缘触发 : (2) 谢谢...
详细了解C++11(1)
大家好呀,我是残念,希望在你看完之后,能对你有所帮助,有什么不足请指正!共同学习交流哦 本文由:残念ing原创CSDN首发,如需要转载请通知 个人主页:残念ing-CSDN博客,欢迎各…...
ITA的去锅盖处理流程
一、说明 锅盖是什么 锅盖的类型有哪些 二、去锅盖处理流程 去锅盖算法首先需要采集一份锅盖模板数据,该模板数据用户可以自定义保存,方便后面的开机重启直接导入使用。去锅盖处理包含两个历程:保存锅盖模板;去锅盖处理。 保存锅盖模板: ( 1 ) 打开采集锅盖模板开关。…...
日志管理系统的系统目标是什么?
在网络安全、数据管理、故障排查等领域,日志都被广泛使用并需要进行有效的管理与分析。因此,日志管理系统的系统目标显得尤为重要,如以下几方面。 1、确保数据的安全性及完整性 在企业和组织的日常运营中,各类信息数据都会通过系统…...
uniapp 底部导航栏tabBar设置后不显示的问题——已解决
uniapp 底部导航栏tabBar设置后不显示的问题——已解决 网上找了一堆解决办法,挨个对着试吧 解决办法一:tabBar里的list第一项和page中的第一项要相同,确实就能显示了。但是问题来了,page中的第一项是入口页,那就意味…...
JVM 类加载器
字节码的结构 魔数u4 cafe babe 版本u4 52 java8 常量池计数器u2 从1开始,0索引留给不需要的情况 常量池 表 #1 -> #计数器-1 类标识符 u2 public final abstrat class annotion interface 之类 类索引u2 名字 父类索引u2 父类名字 接口计数器 u2 接口数…...
《C++长时间运行程序:驯服内存膨胀的“怪兽”》
在 C编程的世界里,当我们编写长时间运行的程序时,内存膨胀问题就像一个隐藏在暗处的“怪兽”,随时可能吞噬我们程序的性能和稳定性。无论是服务器应用程序、大型模拟系统还是其他长时间运行的关键任务软件,有效地处理内存膨胀问题…...
ELK之路第二步——可视化界面Kibana
Kibana 1.安装2.解压3.修改配置4.启动 这部分内容就比较简单了,水一片文章。 1.安装 需要梯子 官网下载链接:https://www.elastic.co/cn/downloads/past-releases/kibana-7-3-0 如果你去官网下载页面,点击下载是404报错,记得切换…...
Nature Medicine病理AI汇总|CONCH:病理图像分析的零样本学习模型·顶刊精析·24-10-30
小罗碎碎念 最近在整理24年发表在Nature Medicine上的病理AI文章,简单列了一个表。 接下来我将按照先后顺序,系统的把这13篇文献分析完。其中底色做了填充的,代表商业公司在本论文中占据了一作或通讯。 本期推文介绍的模型是CONCH࿰…...
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...
wpf在image控件上快速显示内存图像
wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像(比如分辨率3000*3000的图像)的办法,尤其是想把内存中的裸数据(只有图像的数据,不包…...
Leetcode33( 搜索旋转排序数组)
题目表述 整数数组 nums 按升序排列,数组中的值 互不相同 。 在传递给函数之前,nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...
第八部分:阶段项目 6:构建 React 前端应用
现在,是时候将你学到的 React 基础知识付诸实践,构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段,你可以先使用模拟数据,或者如果你的后端 API(阶段项目 5)已经搭建好,可以直接连…...
