[山东大学操作系统课程设计]实验三

0.写在前面(重点)

由于一些突发事件,导致目前大家手里或多或少都有了完整版的答案了。甚至很多学长学姐们写的代码远比我写的要好很多。

但是这个系列我觉得还是稍微坚持下去一点,或许某些地方可以帮到未来的同学们。

还是那句话,有需要可以随时向我反馈你遇到的问题,你的指点就是我最大的动力

1.实验代码解析

注意,这个实验比较特殊,不是想以前一样,直接从nachos源码文件中复制文件到本目录下,然后做拓展。而是重新创建一个新的文件,实现一些功能。

这个文件叫什么,local文件中新增的条目已经向我们指明了,threadsbar.cc()函数。

而且这个函数需要重写什么东西,也很容易了解了,就在这个文件中

至于实验大纲中提到的,关于那个n屏障,我酱在下一个小目录中实现。

2.手把手攻略

这里要说一下n屏障机制

N线程屏障(N-thread barrier)是一种同步机制,用于确保多个线程在达到某个点之前都会被阻塞,直到所有线程都到达该点后才能继续执行。它提供了一种线程同步的方式,以便在多线程环境中协调并发操作。

N线程屏障中的N表示参与屏障同步的线程数量。当N个线程都到达屏障位置时,屏障将打开,所有线程将被释放并可以继续执行后续的操作。如果有任何一个线程到达屏障位置之前发生阻塞(未到达屏障位置),则其他线程也会被阻塞,直到所有线程都准备好后才会继续执行。

而对于这个代码段,我估计写过go语言的同学都不陌生

rendezvousmutex . wait ()
count = count + 1
mutex . signal ()if count == n: barrier . signal ()barrier . wait ()
barrier . signal ()critical point

这是一个比较典型的创建n屏蔽的过程

首先mutex在go语言中,我们经常称之为互斥锁,互斥锁内的资源,每次之允许一个线程进行访问,其他的线程将会存入队列中等待被执行。在nachos中,使用Semaphore实现了mutex这个东西。我们可以用图上的方式完成这些操作

而barrier其实也是通过Semaphore来实现的,在这里我们先不关心是如何实现的,具体的实现和定义我们会放在下面的代码中解释。barrier理想中的状态,是在代码的某处拦住所有的线程,当某个线程发送了signal这个指令的时候,其他被阻塞的线程就”跨过“自己当前所在的wait语句。

因此这一整段代码实现的就是,在第n个线程到达之前,前面n-1个线程都处在被阻塞的状态,第n个线程到达if语句以后,经过判断释放signal信号,让其他线程可以脱离。

而自身则可能会被wait洽住,但是此时已经”逃脱“的线程,重新发送了信号。这样让第n个县城也可以顺利脱困

(至于这个东西需要不需要时间机制。。。我想说的事barrier只是一个逻辑上的概念,尤其是在nachos上的模拟实现,所以底层是存在信号量这一资源的,所谓的”信号“也是通过资源数目来确定能否通行,比如barrier本质上是一个初始资源数目为0的semaphore对象,而mutex为初始资源数目为1的semaphore对象)

3.实验过程分析

首先说明,具体的实验流程和名称在这里先简写了,所以题目可能对不上,不过内容是大致一致的

3.1:分析说明nachos信号量如何实现

信号量主要依靠如下semaphore个类的实现

该类中使用P V两个函数来完成信号量增加和减少的原语操作

另外这个类中还使用了value来模拟”可支配资源“的数目,以及信号等待队列List的实现,这个队列中用来阻塞线程。

3.2:说明并发进程如何创建以及运行

在nachos中,并发进程的创建是通过for循环进行多重创建,生成数个可以并行的thread对象,如图所示

在nachos中,默认每个时刻只有一个线程在运行,因此如果需要调度的话需要Threads类中的yield,sleep,以及finish方法进行辅助。并且还需要scheduler中的这几个方法作为调度逻辑

并发的执行运行则可以在scheduler.cc中的方法看到

ReadyToRun负责进行从就绪转化为运行态

FindNextToRun方法负责将运行态转化为结束态,并且将下一个线程移入

Run方法负责直接执行线程

3.3,修改代码以及实现n屏障机制

在文件夹lab3下面,创建一个名为threadsbar.cc的cpp文件,如图所展示

在lab3文件夹下存在一个readme的文件,里面展示了一个代码框架,我们根据这个代码框架实现了如下的代码,在threadsbar.cc中

//事先说明,需要改动的其实就是这些东西
//我们根据信号量Semaphore这个类来实现互斥锁mutex,以及n线程屏障barrier//首先要导入一些新的包
#include <unistd.h>
#include <stdio.h>#include "copyright.h"
#include "system.h"
#include "synch.h"#define N_THREADS 20    // the number of threads
#define MAX_NAME 16    //设置最大长度“名称”
#define N_TICKS 1000  // the number of ticks to advance simulated time//创建线程队列
Thread *threads[N_THREADS];
char thread_names[N_THREADS][MAX_NAME]; //给每个线程队列都加上一个名字//提前设置好指针
Semaphore *barrier;
Semaphore *mutex;int count=0;void MakeTicks(int n)  // advance n ticks of simulated time n个模拟时间推进
{                        //说实话至少这个函数哥们是没看懂一点的。。。。int i;                //首先是我不会操作系统,其次我不写cppIntStatus oldLevel;   //根据代码框架的提示,在最开始就写好了这个开关来增加时间的方法oldLevel=interrupt->SetLevel(IntOff);for(i=0;i<n;i++){interrupt->SetLevel(IntOff);interrupt->SetLevel(IntOn);}interrupt->SetLevel(oldLevel);
}void BarThread(_int which)   //下面这个其实就是基本实现了
{MakeTicks(N_TICKS);printf("Thread %d rendezvous\n", which);//这个东西被称作rendezvous循环什么的??乱七八糟的//总之就是首先由互斥锁保证,计数器是合理运行的mutex->P();count++;                     mutex->V();/*if(count==N_THREADS){printf("Thread %d is the last===================\n",which);barrier->V();                            //}barrier->P();                               //前面n-1个线程会被阻塞在这里barrier->V();                               //会去解救原本的第n个线程*///好像出现的问题之一是有的线程会觉得自己是最后一个。。。。???没发现这种问题???//好的,加大力度,现在是线程数目为20的时候,随机种子为114514,会发生两个线程都认为自己是最后一个的情况//原因在于临界资源的访问,无论是读写,都应该加上一个互斥锁//在最开始的代码中,对于count的判断并没有使用互斥,导致了两个线程的同时访问//导致的错误:最后一个线程需要处理内存相关的东西,但是当有多个判断自己为最后一个线程的时候,可能会导致内存等其他临界区域发生问题//解决方法:对临界资源的读写仍然是加上互斥锁,如下图代码所示,即可解决这个问题//最后是关于随机种子的情况://rz并非无效,根据实验代码提供的提示,应该是为每个进程分配的时间片不足导致的//使用空循环耗时并没有解决实际问题:首先较少的空循环并不能起到拖延很多时间的作用,其次空循环是在用户状态下执行的任务,对整体的时钟没有什么改变效果//使用linux下的sleep则根本无法解决问题:因为sleep的作用是linux上的进程,而不是nachos上的“线程”,nachos在linux的视角下本身就是一个进程而已//makeTick的开关中断处理了这个问题,由于给的代码框架比较完善,所以在第一次就完善了这个方法//导致后面就没有出现这些问题//所以正确的解决方法就是在makeTick中,增加(根据题目给出的框架,我们默认使用1000来进行实验)//的开关次数,使用nachos内部的“进程”的开关中断进行模拟mutex->P();if(count==N_THREADS){printf("Thread %d is the last===================\n",which);barrier->V();                            }mutex->V();barrier->P();                               //前面n-1个线程会被阻塞在这里barrier->V();                               //会去解救原本的第n个线程printf("Thread %d critical point\n", which);
}void ThreadsBarrier()               //这个函数用来设置县城之间的同步/并发控制
{int i;DEBUG('t',"ThreadsBarrier");     //DEBUG函数使用来干啥的来着??//创建互斥锁以及屏障barrier=new Semaphore("barrier",0);//障碍的信号量设置为0,带波奥这是个屏障mutex=new Semaphore("mutex",1);//互斥锁的信号量设置为1,代表统一时刻只能有一个线程访问这个东西// Create and fork N_THREADS threads   //在这里创造多个线程,也就是县城初始化的部分for(int i = 0; i < N_THREADS; i++) {//...............sprintf(thread_names[i],"thread_%d",i);//...............threads[i]=new Thread(thread_names[i]);threads[i]->Fork(BarThread, i);};
}

其中对于n屏蔽机制,如图所示(代码加上了一些注释,因为这段代码是需要后期改进的,这里是完成了第三步要求的展示。)

使用make指令进行编译,并且根据-rz指令设置随机种子

在这里我们直接使用随机种子114514,并且为了让结果更加明显,我们创建了而是个并发的县城,结果如下

使用指令

./nachos -rz 114514

结果如下

出现了明显的问题,进程0和进程1都认为自己是最后一个进程

这个现象的原因是因为,对于最后的count的读取判断,并没有是互斥枷锁,倒是了0和1都能读取到count=n的情况,导致二者均认为自己可以处理这个问题。

处理方法为:对于if的count判断,也要加上互斥锁

3.4:使用随机种子进行测试,可能会发生-rz失效的情况,如何处理,以及怎么处理

rz确实会发生”无效“的情况,根据实验代码提供的提示,应该是为每个进程分配的时间片不足导致的

1。使用空循环耗时并没有解决实际问题:首先较少的空循环并不能起到拖延很多时间的作用,其次空循环是在用户状态下执行的任务,对整体的时钟没有什么改变效果

2。使用linux下的sleep则根本无法解决问题:因为sleep的作用是linux上的进程,而不是nachos上的“线程”,nachos在linux的视角下本身就是一个进程而已

makeTick的开关中断处理了这个问题,由于给的代码框架比较完善,所以在第一次就完善了这个方法,导致在最开始的测试中就没有出现这些问题,所以正确的解决方法就是在makeTick中,增加(根据题目给出的框架,我们默认使用1000来进行实验)

如图所示,我们进一步填充了maketick函数的内容

void MakeTicks(int n)  // advance n ticks of simulated time n个模拟时间推进
{                        //说实话至少这个函数哥们是没看懂一点的。。。。int i;                //首先是我不会操作系统,其次我不写cppIntStatus oldLevel;   //根据代码框架的提示,在最开始就写好了这个开关来增加时间的方法oldLevel=interrupt->SetLevel(IntOff);for(i=0;i<n;i++){interrupt->SetLevel(IntOff);interrupt->SetLevel(IntOn);}interrupt->SetLevel(oldLevel);
}

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

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

相关文章

Spring MVC数据绑定的几种方法(一)

这篇文章包含spring mvc的默认数据类型绑定和简单数据类型绑定。内容来自实验。 准备&#xff1a; &#xff08;1&#xff09;在IDEA环境中从archetye创建webapp类型的maven项目exp6。 &#xff08;2&#xff09;在src\main目录下创建并标注java源代码文件夹和resources资源文…

NVIDIA GPU Operator install in kubernetes

文章目录 1. 简介2. Kubernetes 安装3. OS配置4. Docker Engine&#xff0c;cri-dockerd安装5. 安装 kubeadm6. GPU-Operator安装 1. 简介 Kubernetes通过设备插件框架提供对特殊硬件资源的访问&#xff0c;如NVIDIA GPU、⽹卡、Infiniband适配器和其他设备。但是&#xff0c;…

基于Java SSM框架实现实现四六级英语报名系统项目【项目源码+论文说明】

基于java的SSM框架实现四六级英语报名系统演示 摘要 本论文主要论述了如何使用JAVA语言开发一个高校四六级报名管理系统&#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;采用B/S架构&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作…

2024美赛数学建模资料---100%获奖资料

很好的教程了 一共二十四章 每一章都是一个模型 并且有matlab编程编码 第一章 线性规划 第二章 整数规划 第三章 非线性规划 第四章 动态规划 第五章 图与网络 第六章 排队论 第七章 对策论 第八章 层次分析法 第九章 插值与拟合 第十章 数据的统计描述和分析 第十一章…

详解Spring对Mybatis等持久化框架的整合

&#x1f609;&#x1f609; 学习交流群&#xff1a; ✅✅1&#xff1a;这是孙哥suns给大家的福利&#xff01; ✨✨2&#xff1a;我们免费分享Netty、Dubbo、k8s、Mybatis、Spring...应用和源码级别的视频资料 &#x1f96d;&#x1f96d;3&#xff1a;QQ群&#xff1a;583783…

自带灯效的气传导耳机,声音当然好听,哈氪聆光体验

现在市场上的蓝牙耳机种类繁多&#xff0c;入耳式的算是主流&#xff0c;但不太适合户外使用 &#xff0c;我平时出门健身、散步的时候&#xff0c;更喜欢用气传导耳机。气传导耳机通常采用挂耳式的设计&#xff0c;耳机不入耳&#xff0c;佩戴舒适度更好&#xff0c;而且稳定性…

Linux安装mongodb数据库(详细)

一、下载安装包 本文使用 tgz 方式,根据服务器类型在官网下载 MongoDB 安装包。官方地址&#xff1a;https://www.mongodb.com/try/download/community 下载方式如图所示&#xff1a; 选择版本 关于 MongoDB 的版本选择&#xff0c;参见如下版本差异&#xff1a; 1、将从官…

Java基本数据类型详解

✨个人主页&#xff1a;全栈程序猿的CSDN博客 &#x1f4a8;系列专栏&#xff1a;Java从入门到精通 ✌座右铭&#xff1a;编码如诗&#xff0c;Bug似流星&#xff0c;持续追求优雅的代码&#xff0c;解决问题如同星辰般自如 Java是一种强类型语言&#xff0c;数据类型在程序中起…

JS不同运算符下的隐式类型转换

目录 运算符 逻辑运算符&#xff08;&&、||、!&#xff09;和 条件表达式&#xff08;if、三元表达式&#xff09; 逻辑运算符 条件表达式 算数运算符&#xff08;*、/、- %、&#xff09;和 关系运算符&#xff08;>、<、、!&#xff09; 算数运算符 关系…

Python实战:批量加密Excel文件指南

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;我是彭涛&#xff0c;今天为大家分享 Python实战&#xff1a;批量加密Excel文件指南&#xff0c;全文3800字&#xff0c;阅读大约10分钟。 在日常工作中&#xff0c;保护敏感数据是至关重要的。本文将引导你通过…

栈和队列的OJ题--13.用队列实现栈

13. 用队列实现栈 225. 用队列实现栈 - 力扣&#xff08;LeetCode&#xff09; /*解题思路&#xff1a; 此题可以用两个队列去实现一个栈&#xff0c;每次始终保持一个队列为空&#xff0c; 入栈操作相当于给非空队列进行入队操作 出栈操作相当于非空队列的队尾元素出队&…

细说CountDownLatch

CountDownLatch 概念 CountDownLatch可以使一个获多个线程等待其他线程各自执行完毕后再执行。 CountDownLatch 定义了一个计数器&#xff0c;和一个阻塞队列&#xff0c; 当计数器的值递减为0之前&#xff0c;阻塞队列里面的线程处于挂起状态&#xff0c;当计数器递减到0时…

【学习笔记】机器学习——GAN

提出于2014年。 GAN由两个神经网络组成&#xff1a;一个试图生成看起来与训练数据相似数据的生成器&#xff0c;以及一个试图从虚假数据中分辨出真实数据的判别器。生成器和判别器在训练期间相互竞争。 对抗训练&#xff08;训练竞争性网络&#xff09;是一种重要的机器学习思想…

工作几年了,你真的懂 Redis 嘛?

大家好&#xff0c;我是伍六七。一个专注于输出 AI 编程内容的在职大厂资深程序员&#xff0c;全国最大 AI 付费社群破局初创合伙人&#xff0c;关注我一起破除 35 诅咒。 Redis 基本上是大部分技术公司都会使用的缓存框架&#xff0c;但是我发现很多程序员其实并不懂 Redis。 …

SSM新闻发布管理系统

SSM毕设分享 序号1&#xff1a;SSM新闻发布管理系统 1 项目简介 Hi&#xff0c;各位同学好&#xff0c;这里是郑师兄&#xff01; 今天向大家分享一个毕业设计项目作品【SSM新闻发布管理系统】 师兄根据实现的难度和等级对项目进行评分(最低0分&#xff0c;满分5分) 难度系数…

三极管在数字电路中的应用

一、认识三极管 三极管拥有3个引脚&#xff0c;分别对应3个级&#xff1a;基极(Base)、发射极&#xff08;Emitter&#xff09;、集电极(Collector)&#xff0c;如下图所示&#xff1b;下图横向左侧的是基极&#xff0c;带箭头的那个引脚就是发射极&#xff0c;另一个就是集电…

【PUSDN】java中easyexcel导入导出带有图片的Excel(main方法方式)

简述 java中easyexcel导入导出带有图片的Excel&#xff08;main方法方式&#xff09;&#xff0c;web方式详见另一篇 由于电脑音频问题&#xff0c;视频暂时没有解说声音&#xff0c; 回头重新补上 前情提示 如果有任何疑问、需求、技术支持&#xff0c;欢迎点赞&#xff0…

JavaWeb-XML

1.常见的配置文件 1.1 properties 数据库的连接就使用properties文件作为配置文件&#xff0c;properties文件中的配置信息是以键值对的形式存储的。 beiluo.jdbc.urljdbc:mysql://localhost:3306/beiluo beiluo.jdbc.drivercom.mysql.cj.jdbc.Driver beiluo.jdbc.usernamer…

【hacker送书活动第7期】Python网络爬虫入门到实战

第7期图书推荐 内容简介作者简介大咖推荐图书目录概述参与方式 内容简介 本书介绍了Python3网络爬虫的常见技术。首先介绍了网页的基础知识&#xff0c;然后介绍了urllib、Requests请求库以及XPath、Beautiful Soup等解析库&#xff0c;接着介绍了selenium对动态网站的爬取和S…

HADOOP::Fsimage和Edits解析

NameNode被格式化之后&#xff0c;将在/opt/module hadoop-3.1.3/data/tmp/dfs/name/curent目录 中产生如下文件 fsimage_ 0000000000000000000 fsimage_ 0000000000000000000.md5 seen_txid VERSION (1) Fsimage文件: HDFS文件系统元数据的一个永久性的检查点&#xff0…