操作系统学习笔记-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࿰…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...

USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...

C++实现分布式网络通信框架RPC(2)——rpc发布端
有了上篇文章的项目的基本知识的了解,现在我们就开始构建项目。 目录 一、构建工程目录 二、本地服务发布成RPC服务 2.1理解RPC发布 2.2实现 三、Mprpc框架的基础类设计 3.1框架的初始化类 MprpcApplication 代码实现 3.2读取配置文件类 MprpcConfig 代码实现…...