HNU-2024操作系统实验-Lab7-信号量与同步

news2024/9/21 0:43:38

一、 实验目的

  1. 理解信号量的基本概念,以及其在进程同步中的作用

  2. 学习使用信号量来实现进程之间的同步

  3. 理解并解决多种并发时可能出现的问题

二、 实验过程

1.实现信息量结构初始化

① 在lab7/src/include目录下新建prt_sem_external.h 头文件

在这里插入图片描述
在这里插入图片描述

下面对该板块进行分析:

这个代码板块主要是实现了一个信号量管理模块的接口,包含了信号量的状态、类型、模式的宏定义、控制块结构体、全局变量和操作信号量的函数。

首先对宏定义进行分析:

  • OS_SEM_UNUSED 和 OS_SEM_USED 用来标识信号量是否在使用。

  • SEM_PROTOCOL_PRIO_INHERIT 表示优先级继承协议。

  • SEM_TYPE_BIT_WIDTH 和 SEM_PROTOCOL_BIT_WIDTH 定义了信号量类型和协议的位宽。

  • MAX_POSIX_SEMAPHORE_NAME_LEN 定义了POSIX信号量名称的最大长度。

  • GET_SEM_LIST 等宏用来操作信号量列表和获取信号量相关信息。

最后定义了一些变量,同时声明了一些外部定义的函数。

② 在lab7/src/kernel/sem目录下新建prt_sem_init.c 文件

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

这段代码主要是定义了信号量的初始化函数,分别分析这三个函数的功能:

  • OsSemInit:这个函数是对信号量管理模块的初始化,它首先调用 OsMemAllocAlign函数分配对齐的内存,用于存储信号量控制块,然后计算最大信号量数量 g_maxSem,同时将分配的内存清零,确保信号量控制块的初始状态为0,最后初始化空闲信号量列表g_unusedSemList、遍历所有信号量控制块,初始化其ID,并将其添加到空闲信号量列表中。

  • OsSemCreate:这个函数是信号量创建函数,它首先检查参数sem_handle信号量句柄(响应的信号)是否不为空,若为空则返回错误,然后关闭中断,防止创建信号量时引发中断,接着从空闲信号量表中取出第一个空闲块,并对其进行初始化,设置信号量的初始值、状态、模式、类型和拥有者,然后根据信号量的类别semType来进行相应操作,若为二进制量,则初始化相关字段,最后将信号量ID以地址间接访问的方式赋值给semHandle,打开中断,完成信号量的初始化。

  • PRT_SemCreate:这个函数是一个封装函数,首先排除不合理的count数,然后调用OsSemCreat函数进行信号量创建。

③ 在src/bsp目录中的os_cpu_armv8_external.h文件加添加定义

在这里插入图片描述

④ 在src/kernel/sem目录下新建prt_sem.c 文件。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这一部分主要是定义了一系列检查等辅助函数,其中OsSemPostErrorCheck函数和OsSemPendParaCheck函数用于检查post操作和pend操作是否有效,接着对其中较为复杂的函数进行分析:

  • OsSemPendListPut函数:该函数将当前运行任务挂接到信号量的等待链表上,首先,此函数将当前运行的任务从就绪列表中移除,然后根据信号量的等待模式(优先级或FIFO),将任务添加到信号量的等待列表中。如果是优先级模式,并且当前任务的优先级高于等待列表中的某些任务,则将其插入到对应合适的位置,否则以FIFO方式添加到列表末尾。

  • OsSemPendListGet函数:此函数首先从信号量的等待列表中取出第一个任务,并将其放入就绪队列,如果取出的任务之前设置了定时等待标志(OS_TSK_TIMEOUT),则清除该标志并从定时等待列表中移除。

接下来分析本实验的两个重点核心函数:PRT_SemPend与PRT_SemPost:

在这里插入图片描述

PRT_SemPend函数实现等待信号相应操作,其两个参数分别代表需要响应的信号以及等待时间,进入函数,本函数首先判断semHandle是否有效,若无效则直接返回错误,接着利用GET_SEM宏获取该信号对应的信号控制块,然后禁用中断,防止在执行Pend操作时引发中断,保证该操作的原子性,然后根据信号控制块对信号量状态、中断活动、任务调度情况以及超时参数进行检查,检查完毕后将该任务挂起,置于信号量等待链表中,直到信号量被释放,即收到该信号的Post操作,若等待时间不为永久,则判断是否超时,超时则返回错误,若等待时间为永久,则调用快速调度函数OsTskScheduleFastPs进行调度,顺利完成后恢复中断并正常返回。

在这里插入图片描述

PRT_SemPost函数与PRT_SemPend函数的检查准备操作非常类似,只是最后一步操作是执行OsSemPostSchePre函数从阻塞队列移除对应信号,并将其加入到信号就绪队列,准备进行任务调度,然后通过OsTskScheduleFastPs函数进行快速任务调度。

⑤ 在src/include目录下的prt_task_external.h文件中加入 OsTskReadyAddBgd()

在这里插入图片描述

⑥ 在src/kernel/task目录中的prt_task.c文件加入 OsTskScheduleFastPs()

在这里插入图片描述

⑦ src/bsp/os_cpu_armv8_external.h 加入 OsTaskTrapFastPs()

在这里插入图片描述

⑧ 在src/include目录中加入prt_sem.h文件

⑨ 最后将所有的新文件加入构建系统

在这里插入图片描述

在这里插入图片描述

至此,信号系统已构建完毕

三、 测试及分析

在main函数中执行任务1与任务2:

正常运行,符合预期情况

四、 Lab7作业

各种并发问题模拟,至少3种。

1.违反原子性缺陷

在这里插入图片描述

观察此段代码,可以发现线程1、线程2都要访问公共指针变量ptr,第一个线程检查指针不为空,然后打印出指针指向的值,第二个线程则是将指针设置为空,对于线程一的操作违反了原子性,就有可能当检查完ptr非空之后,在PRT_Printf函数调用之前引发时钟中断,第二个线程将指针设置为空,当第一个线程恢复执行时,引用空指针导致程序崩溃。(此处随机访问地址空间并打印出其中的值)

在这里插入图片描述

解决方法:给共享变量ptr加锁,确保每个线程访问该变量时都持有锁

在这里插入图片描述

在这里插入图片描述

正常访问执行

2.违反顺序缺陷

在这里插入图片描述

这段代码中线程二的执行已经假定指针ptr已经被初始化,即默认线程一在线程二之前执行,但是一旦线程二优先执行,就会因为引用空指针而产生崩溃

在这里插入图片描述

解决方法:利用信号量,让线程二使用本实验定义的函数Pend,线程一使用函数Post,这样即使线程二优先执行,也会等待线程一初始化指针ptr之后,释放信号量才能继续执行

在这里插入图片描述

在这里插入图片描述

保证了线程一在线程二前运行

3.死锁

在这里插入图片描述

第一个线程持有锁1,正在等待锁2,第二个线程持有锁2,正在等待锁1,死锁就产生了,两个线程互相等待,无法正常继续运行

在这里插入图片描述

4.哲学家进餐问题

在这里插入图片描述

此处模拟的是教材《操作系统导论》中的一个非常有趣的问题–哲学家进餐问题,书中的例子是每个哲学家要进食,必须先拿起左手的筷子,再拿起右手的筷子,同时这些哲学家围成一圈,拿筷子的动作是并发的,这时当所有哲学家拿起左手边的筷子之后,由于每个哲学家的右手筷子是其他哲学家的左手筷子,因此所有哲学家无法再拿起右手的筷子,陷入死锁,此处给出的是解决方案:即让最后一个哲学家先拿右手的筷子,破坏死锁产生的必要条件循环等待,这样就成功让所有哲学家顺利进食:

在这里插入图片描述

5.生产者消费者问题

在这里插入图片描述

这里模拟的是教材中的另一个经典问题:生产者消费者问题,在本程序中,消费者会先进入缓冲区,但由于此时缓冲区为空,消费者阻塞等待生产者的sem_full信号,这时生产者进入缓冲区,往缓冲区中写入内容,此时缓冲区已满,故生产者向消费者发送sem_full信号,自己阻塞,等待消费者将缓冲区内容读完后发送sem_empty信号,如此就实现了对缓冲区资源的互斥访问,生产者写,消费者用,二者互不干扰,有秩序地执行:

在这里插入图片描述

五、 心得体会

  1. 通过这个实验我更为深入地理解了信号量的相关原理

  2. 我理解了信号量及信号量相关函数实现的底层原理

  3. 通过自己模拟教材中的并发问题,我对并发有了更深刻的理解,也使得我将来能够更好地解决这些问题

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

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

相关文章

Apache中使用CGI

Apache24 使用Visual Studio 2022 // CGI2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include <stdio.h> #include <stdlib.h>#include <stdio.h>void main() {//设置HTML语言printf("Content-type:text/html\n\n&q…

LabVIEW优化氢燃料电池

太阳能和风能的发展引入了许多新的能量储存方法。随着科技的发展&#xff0c;能源储存和需求平衡的方法也需要不断创新。智慧城市倡导放弃石化化合物&#xff0c;采用环境友好的发电和储能技术。氢气系统和储存链在绿色能源倡议中起着关键作用。然而&#xff0c;氢气密度低&…

提升Selenium在Chrome上的HTML5视频捕获效果的五个方法

在使用Selenium进行网页自动化测试时&#xff0c;捕获HTML5视频是一个常见的需求。然而&#xff0c;许多开发者发现&#xff0c;在使用Chrome浏览器时&#xff0c;视频捕获效果并不理想&#xff0c;经常出现视频背景为空白的问题。本文将概述五种方法&#xff0c;帮助提升Selen…

Qt:13.多元素控件(QLinstWidget-用于显示项目列表的窗口部件、QTableWidget- 用于显示二维数据表)

目录 一、QLinstWidget-用于显示项目列表的窗口部件&#xff1a; 1.1QLinstWidget介绍&#xff1a; 1.2属性介绍&#xff1a; 1.3常用方法介绍&#xff1a; 1.4信号介绍&#xff1a; 1.5实例演示&#xff1a; 二、QTableWidget- 用于显示二维数据表&#xff1a; 2.1QTabl…

前端/python脚本/转换-使用天地图下载的geojson(echarts4+如果直接使用会导致坐标和其他信息不全)

解决echarts4如果直接使用天地图下载的geojson会导致坐标和其他信息不全 解决方法是使用python脚本来补全其他信息&#xff1a;center&#xff0c;level&#xff0c;adcode等内容 前提是必须有一个之前使用的json文件&#xff08;需要全一点的数据供echarts使用&#xff09; …

单端口RAM

目录 描述 输入描述&#xff1a; 输出描述&#xff1a; 参考代码 描述 题目描述&#xff1a; 设计一个单端口RAM&#xff0c;它有&#xff1a; 写接口&#xff0c;读接口&#xff0c;地址接口&#xff0c;时钟接口和复位&#xff1b;存储宽度是4位&#xff0c;深度128。…

C语言 | Leetcode C语言题解之第228题汇总区间

题目&#xff1a; 题解&#xff1a; char** summaryRanges(int* nums, int numsSize, int* returnSize) {char** ret malloc(sizeof(char*) * numsSize);*returnSize 0;int i 0;while (i < numsSize) {int low i;i;while (i < numsSize && nums[i] nums[i …

【公益案例展】亚运天穹——践行亚运理念,筑牢安全防线

‍ 安恒信息公益案例 本项目案例由安恒信息投递并参与数据猿与上海大数据联盟联合推出的 #榜样的力量# 《2024中国数据智能产业最具社会责任感企业》榜单/奖项”评选。 大数据产业创新服务媒体 ——聚焦数据 改变商业 杭州第19届亚运会是中国第三次举办亚洲最高规格的国际综合…

C++ | Leetcode C++题解之第228题汇总区间

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<string> summaryRanges(vector<int>& nums) {vector<string> ret;int i 0;int n nums.size();while (i < n) {int low i;i;while (i < n && nums[i] nums[i - 1] …

【线性表,线性表中的顺序表和链表】

目录 1、线性表的定义和基本操作1.1、线性表的定义1.2、线性表的基本操作 2、顺序表和链表的比较2.1、顺序表2.1.1、顺序表的定义和特点2.1.2、顺序表的实现&#xff08;1&#xff09;顺序表的静态分配&#xff1a;&#xff08;2&#xff09;顺序表的动态分配 2.1.3、顺序表的基…

Android 性能优化之内存优化

文章目录 Android 性能优化之内存优化内存问题内存抖动内存泄露内存溢出 检测工具Memory ProfilerMemory AnalyzerLeakCanary 内存管理机制JavaAndroid 解决内存抖动问题模拟问题代码使用Memory Profiler工具检测优化技巧 内存泄露问题模拟问题代码使用LeakCanary工具检测优化技…

【常见开源库的二次开发】基于openssl的加密与解密——openssl认识与配置(一)

一、什么是openssl&#xff1f; OpenSSL 是一个开源的软件库&#xff0c;它提供了一系列加密工具和协议&#xff0c;主要用于实现安全通信&#xff0c;如在网络上的数据传输。它支持多种加密算法&#xff0c;包括对称加密、非对称加密、散列函数、伪随机数生成器、数字签名、密…

论文学习_An Empirical Study of Deep Learning Models for Vulnerability Detection

1. 引言 研究背景:近年来,深度学习漏洞检测工具取得了可喜的成果。最先进的模型报告了 0.9 的 F1 分数,并且优于静态分析器。结果令人兴奋,因为深度学习可能会给软件保障带来革命性的变化。因此,IBM、谷歌和亚马逊等行业公司非常感兴趣,并投入巨资开发此类工具和数据集。…

threadx netxduo stm32f407上实现http server

这次用的是CubeIDE CubeMX 要把NX_APP的mem分配的大一些&#xff0c;在app_azure_rtos.c中&#xff0c;我给的是40*1024&#xff0c;如果给的不够&#xff0c;会导致后面无法分配pool和thread等等 需要用到filex 要在CubeMX里面勾选上&#xff0c;还要用到http_server和dhcp …

苹果手机抹机(马来西亚)操作步骤

苹果手机抹机&#xff08;马来西亚&#xff09;操作步骤 操作环境操作步骤 操作环境 苹果6s&#xff0c;没有插卡&#xff0c;就连接上了一个wifi 操作步骤

YOLOv10改进 | Conv篇 | 利用FasterBlock二次创新C2f提出一种全新的结构(全网独家首发,参数量下降70W)

一、本文介绍 本文给大家带来的改进机制是利用FasterNet的FasterBlock改进特征提取网络&#xff0c;将其用来改进ResNet网络&#xff0c;其旨在提高计算速度而不牺牲准确性&#xff0c;特别是在视觉任务中。它通过一种称为部分卷积&#xff08;PConv&#xff09;的新技术来减少…

小白的OS Copilot 产品测评

背景 通过群友介绍才知OS Copilot 。不想错过任何优秀的AI产品。随着互联网的发展和时代的进步&#xff0c;要紧跟时代&#xff0c;了解市面上的优秀的AI科技产品。 OS Copilot 产品体验评测 1&#xff09;您的角色是什么&#xff1f;开发、运维、学生&#xff1f;如果使用O…

微软推出全新的学习网站 Microsoft Learn

微软官方宣布推出全新的学习网站 Microsoft Learn&#xff0c;供开发人员学习 Microsoft 技术。 该网站包含所有 Microsoft 产品和服务(从 HoloLens 到 Azure)的技术文档。提供了超过 80 小时的学习内容&#xff0c;涉及 Azure、Dynamics 365、PowerApps、Microsoft Flow 和 Po…

杜比全景声——空间音频技术

什么是杜比&#xff1f;是否是标清、高清、超清之上的更清晰的格式&#xff1f;杜比全景声 和传统多声道立体声的差别&#xff1f;杜比全景声音频的渲染方式&#xff1f;车载平台上杜比技术的应用&#xff1f; 杜比技术的起源 杜比实验室&#xff08;Dolby Laboratories&…

谷歌内置AI部署

感谢阅读 准备工作开启功能查看下载情况安装插件效果截图网页版地址&#xff08;需进行前面的所有步骤&#xff09; 准备工作 点我下载谷歌dev版本 注意这个版本不需要卸载之前版本 开启功能 使用下载的浏览器依次导航到下面两个地方&#xff0c;然后点击enablebypass以及en…