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

news2025/6/15 19:30:40

0.写在前面(重点)

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

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

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

1.实验代码解析

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

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

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

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

2.手把手攻略

这里要说一下n屏障机制

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

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

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

rendezvous

mutex . 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;                //首先是我不会操作系统,其次我不写cpp
   IntStatus 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;                //首先是我不会操作系统,其次我不写cpp
   IntStatus oldLevel;   //根据代码框架的提示,在最开始就写好了这个开关来增加时间的方法
   oldLevel=interrupt->SetLevel(IntOff);
   for(i=0;i<n;i++){
      interrupt->SetLevel(IntOff);
      interrupt->SetLevel(IntOn);
   }
   interrupt->SetLevel(oldLevel);
}

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

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

相关文章

百度智能云文字识别使用问题解决合集

1.创建试用程序时需要16位的签名MD5 解决方法&#xff1a;使用Java8 201版本及以下的jdk创建签名 下载地址&#xff1a;http://www.codebaoku.com/jdk/jdk-oracle-jdk1-8.html#jdk8u201 生成签名代码&#xff1a;keytool -genkeypair -v -keystore D:\key.jks -storetype PKC…

rdf-file:SM2加解密

一&#xff1a;SM2简介 SM2是中国密码学算法标准中的一种非对称加密算法&#xff08;包括公钥和私钥&#xff09;。SM2主要用于数字签名、密钥交换和加密解密等密码学。 生成秘钥&#xff1a;用于生成一对公钥和私钥。公钥&#xff1a;用于加密数据和验证数字签名。私钥&…

YOLOv8改进 | 2023 | 给YOLOv8换个RT-DETR的检测头(重塑目标检测前沿技术)

一、本文介绍 本文给大家带来是用最新的RT-DETR模型的检测头去替换YOLOv8中的检测头。RT-DETR号称是打败YOLO的检测模型&#xff0c;其作为一种基于Transformer的检测方法&#xff0c;相较于传统的基于卷积的检测方法&#xff0c;提供了更为全面和深入的特征理解&#xff0c;将…

Safe and Practical GPU Computation in TrustZone论文阅读笔记

Safe and Practical GPU Computation in TrustZone 背景知识&#xff1a; youtube GR视频讲解链接&#xff1a;ASPLOS’22 - Session 2A - GPUReplay: A 50-KB GPU Stack for Client ML - YouTube GPU软件栈&#xff1a; 概念&#xff1a;"GPU软件栈"指的是与GPU硬件…

【代码】基于改进差分进化算法的微电网调度研究matlab

程序名称&#xff1a;基于改进差分进化算法的微电网调度研究 实现平台&#xff1a;matlab 代码简介&#xff1a;了进一步提升差分进化算法的优化性能,结合粒子群(PSO)算法的进化机制,提出一种混合多重随机变异粒子差分进化算法(DE-PSO)。所提算法不仅使用粒子群差分变异策略和…

⭐ Unity 里让 Shader 动画在 Scene 面板被持续刷新

写 Unity Shader的时候&#xff0c;只有播放状态下的 Game 面板能看到Shader 顺畅的动态效果&#xff0c;不方便。 想要带有动态效果的 Shader 在 Scene 面板持续更新动画&#xff0c;只需要打开一个开关就能让 Scene 持续刷新动画了。 感谢大家的观看&#xff0c;您的点赞和关…

nrm安装以及常用命令

做为开发者&#xff0c;我们经常会使用到淘宝镜像去安装一些包。基本上设置的都是cnpm这种。但是这一长串其实很难记住。这时&#xff0c;我们可以用nrm进行镜像的切换更为方便。 npm install -g cnpm --registryhttps://registry.npm.taobao.org 安装方法 npm install nrm …

代码随想录算法训练营第38天| 509. 斐波那契数 70. 爬楼梯 746. 使用最小花费爬楼梯

JAVA代码编写 动态规划&#xff08;Dynamic Programming&#xff09; 一个问题可以划分为多个子问题&#xff0c;且子问题之间有关联&#xff0c;就可以使用动态规划。 动态规划问题步骤&#xff1a; 确定dp数组&#xff08;dp table&#xff09;以及下标的含义确定递推公式…

Linux操作系统 2.Linux基础命令

Linux基础命令&#xff0c;掌握这一套清晰的讲解就够啦&#xff01; 本篇博客给大家带来的是Linux的基础命令和vi编辑器 感谢大家收看~ 一、Linux目录结构 Linux的目录结构是一个树形结构&#xff0c;Linux只有一个根目录 / 所有文件都存在/下面 Linux路径的描述方式 Linux系…

通过查看ThreadLocal的源码进行简单理解

目录 为什么要使用ThreadLocal&#xff1f; 简单案例 ThreadLocal源码分析 断点跟踪 为什么要使用ThreadLocal 在多线程下&#xff0c;如果同时修改公共变量可能会存在线程安全问题&#xff0c;JDK虽然提供了同步锁与Lock等方法给公共访问资源加锁&#xff0c;但在高并发…

OpenCV-Python:计算机视觉框架

1.背景 俗话说“工欲善其事必先利其器”&#xff0c;想要学好计算机视觉&#xff0c;需要借助于相关的计算机视觉库&#xff0c;这样在进行学习的时候可以达到事半功倍的效果。 2.早期计算机视觉框架概述 Matlab的最早历史可以追溯到1970年&#xff0c;开始是作为数据处理工…

YUVRGB

一、直观感受 根据上面的图片&#xff0c;不难看出&#xff1a; RGB的每个分量&#xff0c;是对当前颜色的一个亮度值Y分量对呈现出清晰的图像有着很大的贡献Cb、Cr分量的内容不太容易识别清楚YUV将亮度信息&#xff08;Y&#xff09;与色度信息&#xff08;UV&#xff09;分离…

最多不一定最好,只有适合的才是最好的!电脑的内存多大才是合理的

RAM&#xff0c;或称随机存取存储器&#xff0c;是最好的笔记本电脑和最好的电脑最重要的组成部分之一。硬盘驱动器&#xff08;HDD&#xff09;或固态驱动器&#xff08;SSD&#xff09;存储可以被视为电脑的长期内存&#xff0c;内存是其短期内存。内存可以跟踪后台运行的应用…

P6 链表 插入数据节点 尾插法指定节点插入

目录 前言 ​编辑 01 链表指定节点后插入数据&#xff08;根据节点号插入&#xff09; 测试代码 02 链表指定节点后插入数据&#xff08;根据节点的数据插入&#xff09; 尾插法的代码 前言 …

for循环定义域问题

记录一个偶然发现的问题&#xff0c;代码如下 int main(int argc, char *argv[], char *envp[]){for(int i 1; i < 10; i);printf("%d",i); return 0; } 可以看到for循环后加了一个分号&#xff0c;按理说应该报变量i未定义的错误&#xff0c;但此时在编译器中…

RCE绕过

1.[SCTF 2021]rceme 总结下获取disabled_funciton的方式 1.phpinfo() 2.var_dump(ini_get(“disable_functions”)); 3.var_dump(get_cfg_var(“disable_functions”)); 其他的 var_dump(get_cfg_var(“open_basedir”)); var_dump(ini_get_all()); <?php if(isset($_POS…

使用coco数据集进行语义分割(1):数据预处理,制作ground truth

如何coco数据集进行目标检测的介绍已经有很多了&#xff0c;但是关于语义分割几乎没有。本文旨在说明如何处理 stuff_train2017.json stuff_val2017.json panoptic_train2017.json panoptic_val2017.json&#xff0c;将上面那些json中的dict转化为图片的label mask&am…

C++入门篇第十篇----继承

前言&#xff1a; 本篇我们将开始讲解C的继承&#xff0c;我想要说的是&#xff0c;C的主体基本就是围绕类和对象展开的&#xff0c;继承也是以类和对象为主体&#xff0c;可以说&#xff0c;C相较于C优化的地方就在于它对于结构体的使用方法的高度扩展和适用于更多实际的场景…

ffmpeg 任意文件读取漏洞/SSRF漏洞 (CVE-2016-1897/CVE-2016-1898)

漏洞描述 影响范围 FFmpeg 2.8.x < 2.8.5FFmpeg 2.7.x < 2.7.5FFmpeg 2.6.x < 2.6.7FFmpeg 2.5.x < 2.5.10 漏洞环境及利用 搭建docker环境 访问8080端口看到上传界面 由于vulhub并没有讲述该漏洞如何复现&#xff0c;我们需要进入环境查看源码 <?php if(!…

电大搜题:开启你的学习新篇章

广西开放大学&#xff0c;作为一所具有悠久历史和丰富经验的广播电视大学&#xff0c;在教育领域享有盛誉。如今&#xff0c;随着科技的迅猛发展&#xff0c;广西开放大学推出了电大搜题微信公众号&#xff0c;为广大学子提供了一个便捷、高效的学习工具。 电大搜题微信公众号…