西北工业大学操作系统实验_OS3(2)
- 格式:doc
- 大小:464.00 KB
- 文档页数:15
数字电路技术实验报告一、学号: 姓名: 日期:实验目的:(1).用数码显示管实现0.1.2.3.4.0.3.0.3.4;(2).用74LS90,5421BCD码实现模十计数;二、实验设备:(1).数字电路试验箱;(2).数字双踪示波器;(3).函数信号发生器;(4).集成电路: 74LS90;(5).集成电路: 74LS00;三、实验原理:计数是一种最简单的基本运算计数器在数字系统中主要是对脉冲的个数进行计数以实现测量、计数和控制的功能同时兼有分频功能。
计数器按计数进制分为二进制计数器十进制计数器和任意进制计数器按计数单元中触发器所接收计数脉冲和翻转顺序分为异步计数器同步计数器按计数功能分有加法计数器减法计数器可逆双向计数器等。
异步清零2-5-10进制异步计数器74LS9074LS90是一块2-5-10进制异步计数器它由四个主从JK触发器和一些附加门电路组成其中一个触发器构成一位二进制计数器另三个触发器构成异步五进制计数器。
在74LS90计数器电路中设有专用置0端R01 R02和置9端S91 S92 当R1=R2=S1=S2=0时时钟从CP1引入Q0输出为二进制时钟从CP2引入Q3输出为五进制时钟从CP1引入Q0接CP2即二进制的输出与五进制的输入相连则Q3Q2Q1Q0输出为十进制8421BCD 码时钟从CP2引入而Q3接CP1即五进制的输出与二进制的输入相连Q0Q3Q2Q1输出为十进制5421BCD码。
74LS90管脚定义74LS00管脚定义74LS90功能表四、实验内容:(1).用74LS90实现0123403034 (2).用5421BCD实现计数;五、实验结果:(1).列出真值表;(2).画出卡诺图;(3).按化简结果连接图;(循环数字列表)(1).F8=0;.四变量卡诺图:F 2=Q .Q .Q .Q 1020;F 1=Q 1;(5).把F 8接地;F 4接Q3;F 2与相接Q .Q .Q .Q 1020;F 1与Q 1链接;六、心得体会:这次实验综合性较强, 主要考察了我们从实际问题中抽象出逻辑函数的能力。
北航ARM9实验报告:实验3uCOS-II实验北航 ARM9 实验报告:实验 3uCOSII 实验一、实验目的本次实验的主要目的是深入了解和掌握 uCOSII 实时操作系统在ARM9 平台上的移植和应用。
通过实际操作,熟悉 uCOSII 的任务管理、内存管理、中断处理等核心机制,提高对实时操作系统的理解和应用能力,为后续的嵌入式系统开发打下坚实的基础。
二、实验环境1、硬件环境:ARM9 开发板、PC 机。
2、软件环境:Keil MDK 集成开发环境、uCOSII 源代码。
三、实验原理uCOSII 是一个可裁剪、可剥夺型的多任务实时内核,具有执行效率高、占用空间小、实时性能优良和可扩展性强等特点。
其基本原理包括任务管理、任务调度、时间管理、内存管理和中断管理等。
任务管理:uCOSII 中的任务是一个独立的执行流,每个任务都有自己的堆栈空间和任务控制块(TCB)。
任务可以处于就绪、运行、等待、挂起等状态。
任务调度:采用基于优先级的抢占式调度算法,始终让优先级最高的就绪任务运行。
时间管理:通过系统时钟节拍来实现任务的延时和定时功能。
内存管理:提供了简单的内存分区管理和内存块管理机制。
中断管理:支持中断嵌套,在中断服务程序中可以进行任务切换。
四、实验步骤1、建立工程在 Keil MDK 中创建一个新的工程,选择对应的 ARM9 芯片型号,并配置相关的编译选项。
2、导入 uCOSII 源代码将 uCOSII 的源代码导入到工程中,并对相关的文件进行配置,如设置任务堆栈大小、系统时钟节拍频率等。
3、编写任务函数根据实验要求,编写多个任务函数,每个任务实现不同的功能。
4、创建任务在主函数中使用 uCOSII 提供的 API 函数创建任务,并设置任务的优先级。
5、启动操作系统调用 uCOSII 的启动函数,使操作系统开始运行,进行任务调度。
6、调试与测试通过单步调试、查看变量值和输出信息等方式,对系统的运行情况进行调试和测试,确保任务的执行符合预期。
西北⼯业⼤学操作系统实验_OS1(5)班级:10011007 学号:2010302541 姓名:陈⼀凡实验⼀Linux操作系统的安装及使⽤1. 实验⽬的学习Linux操作系统的安装,体会操作系统为了⽅便⽤户,不断改进的安装过程;熟悉Linux系统的登录和退出,并熟悉它常⽤命令的操作使⽤⽅法。
2. 实验内容1)Linux操作系统的安装(1) 收集硬件配置资料(硬盘空间⼤⼩、显卡类型、显存⼤⼩、⽹卡类型等基本信息);(2) 对于要安装Linux⽽⼜没有预留出⾃由空间,可利⽤Linux光盘⾃带的分区⼯具来拆分基本分区;也可以利⽤DOS下的调整分区程序PQMagic来拆分基本分区或逻辑分区,并将PQMagic安装在另⼀个分区中;(3) Linux对不同介质的安装⽅法(直接从光盘引导完成安装,要求CMOS和光盘都能⽀持光盘引导;从硬盘完成安装,可事先将Linux软件包拷⼊硬盘的⼀个分区,将Linux安装到硬盘的另⼀个分区;⽹络安装,通过⽹络⽂件系统NFS或FTP 并安装到硬盘。
);(4) 使⽤FDISK添加Linux主分区和交换分区(swap);(5) 格式化分区;(6) 选择安装内容;(7) 设置root⽤户的⼝令;(8) 设置⽹卡的中断向量号、I/O地址、DNS和⽹络的⼦⽹掩码等;(9) 安装LILO,实现操作系统的双引导。
2)Linux操作系统的使⽤(1) 登录、退出和关闭系统;(2) man命令的使⽤;(3) –help命令的使⽤;(4) dir(ls)命令的使⽤;(5) less(more)分页浏览⽂件命令的使⽤;(6) touch命令的使⽤;(7) whatis命令的使⽤;(8) apropos命令的使⽤;(9) locate命令的使⽤;(10) whereis命令的使⽤;(11) find命令的使⽤;(12) sort命令的使⽤;(13) tar命令的使⽤;(14) 解压缩归档⽂件命令的使⽤;(15) mc程序的使⽤;(16)cd改变⽬录;(17)pwd查看当前⽬录;(18)mkdir创建新⽬录;(19)cp⽂件拷贝;(20)cat在屏幕上显⽰⽂件内容3)C语⾔程序的编译Linux环境下C语⾔使⽤gcc编译器对程序进⾏编译。
题目:1、修改udp实验程序完成两台电脑通讯2、修改tcp实验程序完成两台电脑通讯3、修改IP源代码实现只调用一个函数**: ***学号:**********班号:10011303时间:2015-12-25计算机学院目录摘要1 目的 .................................................... 错误!未定义书签。
2 要求 (1)3 相关知识 (1)4 实验内容及过程................................. 错误!未定义书签。
5参考文献 .. (4)1、实验目的1.学习UDP和TCP及IP的通讯原理。
2.掌握Socket的编程方法。
3.培养学生自己的创新实验的能力。
4、训练修改实验代码能力。
2、实验要求1、熟悉UDP和TCP通讯的原理及socket编程。
2、自己修改UDP和TCP协议代码中的错误部分,完成两台电脑之间通讯。
3、修改IP源代码使所有外部调用函数都放在一个主函数里面。
3、相关知识1、UDP协议UDP协议[2]的全称是用户数据包协议[3],在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。
在OSI模型中,在第四层——传输层,处于IP协议的上一层。
UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。
UDP用来支持那些需要在计算机之间传输数据的网络应用。
包括网络视频会议系统在内的众多的客户/服务器模式的网络应用都需要使用UDP协议。
UDP协议从问世至今已经被使用了很多年,虽然其最初的光彩已经被一些类似协议所掩盖,但是即使是在现在,UDP仍然不失为一项非常实用和可行的网络传输层协议。
与所熟知的TCP(传输控制协议)协议一样,UDP协议直接位于IP(网际协议)协议的顶层。
根据OSI(开放系统互连)参考模型,UDP和TCP都属于传输层协议。
UDP协议的主要作用是将网络数据流量压缩成数据包的形式。
西北工业大学《综合创作训练》实验报告学院:软件与微电子学院学号:姓名:杜伊专业:软件工程实验时间: 2016年3月实验地点:毅字楼311 指导教师:陈勇西北工业大学2016 年 3 月问答题:(1)Windows支持哪几种坐标系统,你的程序采用的是哪种?答:Windows 一共支持8中不同的坐标系统,分别是MM_TEXT,MM_LOMETRIC,MM_HIMETRIC,MM_LOENGLISH,MM_HIENGLISH,MM_TWIPS,MM_ISOTROPIC, MM_ANISOTROPIC。
我的程序采用的是MM_ANISOTROPIC。
(2)GDI和GDI+:GDI在全称是Graphics Device Interface,即图形设备接口。
是图形显示与实际物理设备之间的桥梁。
GDI接口是基于函数,虽然使程序员省力不少,但是编程方式依然显得麻烦。
例如显示一张位图,我们需要进行“创建位图,读取位图文件信息,启用场景设备,调色板变化“等一系列操作。
然而有了GDI+,繁琐的步骤再次被简化。
顾名思义,GDI+就是GDI的增强版,它是微软在Windows 2000以后操作系统中提供的新接口。
GDI+主要功能:GDI+主要提供以下三种功能:(1) 二维矢量图形:GDI+提供了存储图形基元自身信息的类(或结构体)、存储图形基元绘制方式信息的类以及实际进行绘制的类;(2) 图像处理:大多数图片都难以划定为直线和曲线的集合,无法使用二维矢量图形方式进行处理。
因此,GDI+为我们提供了Bitmap、Image等类,它们可用于显示、操作和保存BMP、JPG、GIF等图像格式。
(3) 文字显示:GDI+支持使用各种字体、字号和样式来显示文本。
相比于GDI,GDI+是基于C++类的对象化的应用程序接口,因此用起来更为简单。
GDI的核心是设备上下文,GDI函数都依赖于设备上下文句柄,程序运行结果展示:四、实验总结122。
实验七消息及其传送机制一、实验目的(1)了解什么是消息。
(2)熟悉消息传送的机理。
二、实验内容与要求1、消息的创建、发送和接收。
使用系统调用msgget( ),msgsnd( ),msgrev( ),及msgctl( )编制一长度为256Bytes的消息发送和接收的程序,将自己的进程号传递给对方,并输出至屏幕。
2、对整个实验过程进行分析总结,给出详细步骤。
三、实验过程1、编写程序实现消息的创建、发送和接收。
将参考程序用vi编辑器录入,然后编译执行。
1、client.c#include <unistd.h>#include <stdio.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>#define MSGKEY 75 /*定义一个消息关键字*/struct msgform /*定义一个结构,它是一个消息的模式,只说明结构的形式*/{ long mtype; /*消息类型*/char mtext[256]; /*消息正文数组*/};int main(){{struct msgform msg; /*定义msg是前面说明的消息结构类型的变量*/int msggid,pid,*pint;msggid=msgget(MSGKEY,0777); /*用系统调用创建一个消息队列*/pid=getpid(); /*获得当前进程的PID*/printf(“client:pid=%d\n”, pid);pint=(int*)msg.mtext; /*将消息正文的头指针赋给指针变量pint*/*pint=pid;msg.mtype=1; /*指定客户进程的消息类型为1*/msgsnd(msggid,&msg,sizeof(int),0); /*向msggid的消息队列发送消息msg*/msgrcv(msggid,&msg,256,pid,0); /*接收pid类型的消息 */printf(“client:receive from pid %d\n”,*pint);return 0;}2、server.c#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include < signal.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>#define MSGKEY 75 /*定义一个消息关键字*/struct msgform /*定义一个与客户端相同的消息关键字*/{ long mtype; /*消息类型*/char mtext[256]; /*消息正文数组*/}msg; /*也可以使用这种方式说明消息结构变量*/void cleanup(int signo); /*说明一个外部函数*/int msgqid;int main(){int i,pid,*pint;for ( i=0; i<23; i++) /*对22个软中断的特殊处理*/signal(i, cleanup); /*若收到22个软中断,转向执行cleanup*/msggid=msgget(MSGKEY,0777|IPC_CREAT); /*创建一个与客户程序相同关键字的消息队列,但它的标志是0777与IPC_CREAT 做“或”操作的结果*/ printf(“server:pid=%d\n”, getpid()); /*输出服务端的进程ID*/for(;;) /*用无限循环完成下列语句*/{ msgrcv(msggid,&msg,256,1,0); /*接收来自客户进程或类型为1的消息 */ pint=(int*)msg.mtext; /*将客户端的消息正文传递给pint*/pid=*pint; /*将读出消息指针送pid,此时*pint中是客户进程的pid值*/printf(“server:receive from pid %d\n”,pid);msg.mtype=pid; /*已接受客户进程的pid为消息类型*/*pint=getpid(); /*以本进程pid作为消息构成消息传递内容*/msgsnd(msggid,&msg,sizeof(int),0); /*发送消息*/}}void cleanup(int signo){ msgctl(msggid , IPC_RMID , 0); /*删除消息队列*/exit(0);}如下图所示:client.cserver.c运行结果如下所示:2、思考题(1)单独执行client或server 有什么结果?(2)执行一个server程序,多次执行client有什么结果?(3)消息机制与管道通信的区别?在消息机制中,进程间的数据交换是以格式化的message为单位,程序员直接利用操作系统提供的一组通信命令,不仅能实现大量的数据传递,而且还是隐藏通信细节,是通信过程对用户透明,减少通信程序的复杂性。
操作系统实验
(课程设计)实验报告
学院
专业
班级/学号
学生姓名
成绩
实验地点_
实验日期___ __
指导教师_____ ___ _____
(课程上机)实验报告
1.实验名称、实验目的、实验内容、实验要求由教师确定,实验前由教师事先填好,然后作为实验报告模版供学生使用;
2.实验准备由学生在实验或上机之前填写,教师应该在实验前检查;
3.实验过程由学生记录实验的过程,包括操作过程、遇到哪些问题以及如何解决等;
4.实验总结由学生在实验后填写,总结本次实验的收获、未解决的问题以及体会和建议等;
5.源程序、代码、具体语句等,若表格空间不足时可作为附录另外附页。
计算机操作系统实验-运行用户态程序(总13页)--本页仅作为文档封面,使用时请直接删除即可----内页可以根据需求调整合适字体及大小--西北工业大学操作系统实验实验报告一、实验目的掌握在GeekOS系统用户态模式下加载并运行可执行程序的方法。
二、实验要求1. 按照实验讲义P127页中的设计要求,实现在用户态模式下加载并运行可执行程序的代码,给出关键函数的代码以及实验结果。
三、实验过程及结果答:核心函数代码如下:================== ===============*/Set_Kernel_Stack_Pointer(esp0);ffsetInFile=proHeader->offset;exeFormat->segmentList[i].lengthInFile=proHeader->fileSize;exeFormat->segmentList[i].startAddress=proHeader->vaddr;exeFormat->segmentList[i].sizeInMemory=proHeader->memSize;exeFormat->segmentList[i].protFlags=proHeader->flags;proHeader++;}return 0;}=================== ===================//需在此文件各函数前增加一个函数,此函数的功能是按给定的大小创建一个用户级进程上下文,具体实现如下://函数功能:按给定的大小创建一个用户级进程上下文static struct User_Context* Create_User_Context(ulong_t size){struct User_Context * UserContext;size = Round_Up_To_Page(size);UserContext = (struct User_Context *)Malloc(sizeof(struct User_Context)); if (UserContext != 0)UserContext->memory = Malloc(size);//为核心态进程elsegoto fail;//内存为空if (0 == UserContext->memory)goto fail;memset(UserContext->memory, '\0', size);UserContext->size = size;//以下为用户态进程创建LDT(段描述符表)//新建一个LDT描述符UserContext->ldtDescriptor = Allocate_Segment_Descriptor();if (0 == UserContext->ldtDescriptor)goto fail;//初始化段描述符Init_LDT_Descriptor(UserContext->ldtDescriptor, UserContext->ldt, NUM_USER_LDT_ENTRIES);//新建一个LDT选择子UserContext->ldtSelector = Selector(KERNEL_PRIVILEGE, true,Get_Descriptor_Index(UserContext->ldtDescriptor));//新建一个文本段描述符Init_Code_Segment_Descriptor(&UserContext->ldt[0],(ulong_t) UserContext->memory,size / PAGE_SIZE,USER_PRIVILEGE);//新建一个数据段Init_Data_Segment_Descriptor(&UserContext->ldt[1],(ulong_t) UserContext->memory,size / PAGE_SIZE,USER_PRIVILEGE);//新建数据段和文本段选择子UserContext->csSelector = Selector(USER_PRIVILEGE, false, 0);UserContext->dsSelector = Selector(USER_PRIVILEGE, false, 1);//将引用数清0UserContext->refCount = 0;return UserContext;fail:if (UserContext != 0){if (UserContext->memory != 0){Free(UserContext->memory);}Free(UserContext);}return 0;}--------------------------------------------//摧毁用户上下文void Destroy_User_Context(struct User_Context* userContext) {//TODO("Destroy a User_Context");//释放占用的LDTFree_Segment_Descriptor(userContext->ldtDescriptor);userContext->ldtDescriptor=0;//释放内存空间Free(userContext->memory);userContext->memory=0;//释放userContext本身占用的内存Free(userContext);userContext=0;}----------------------------------------------int Load_User_Program(char *exeFileData,ulong_t exeFileLength,struct Exe_Format *exeFormat,const char *command,struct User_Context**pUserContext){//TODO("Load a user executable into a user memory space using segmentation");int i;ulong_t maxva = 0;//要分配的最大内存空间unsigned numArgs;//进程数目ulong_t argBlockSize;//参数块的大小ulong_t size, argBlockAddr;//参数块地址struct User_Context *userContext = 0;//计算用户态进程所需的最大内存空间for (i = 0; i < exeFormat->numSegments; ++i) {//struct Exe_Segment *segment = &exeFormat->segmentList[i];ulong_t topva = segment->startAddress + segment->sizeInMemory; /* FIXME: range check */if (topva > maxva)maxva = topva;}Get_Argument_Block_Size(command, &numArgs, &argBlockSize);//获取参数块信息size = Round_Up_To_Page(maxva) + DEFAULT_USER_STACK_SIZE;argBlockAddr = size;size += argBlockSize;userContext = Create_User_Context(size);//按相应大小创建一个进程if (userContext == 0)//如果为核心态进程return -1;for (i = 0; i < exeFormat->numSegments; ++i) {struct Exe_Segment *segment = &exeFormat->segmentList[i];//根据段信息将用户程序中的各段内容复制到分配的用户内存空间memcpy(userContext->memory + segment->startAddress, exeFileData + segment->offsetInFile,segment->lengthInFile);}//格式化参数块Format_Argument_Block(userContext->memory + argBlockAddr, numArgs, argBlockAddr, command);//初始化数据段,堆栈段及代码段信息userContext->entryAddr = exeFormat->entryAddr;userContext->argBlockAddr = argBlockAddr;userContext->stackPointerAddr = argBlockAddr;//将初始化完毕的User_Context赋给*pUserContext*pUserContext = userContext;return 0;//成功}----------------------------------------------//将用户态的进程复制到内核缓冲区bool Copy_From_User(void* destInKernel, ulong_t srcInUser, ulong_t bufSize) {struct User_Context * UserContext = g_currentThread->userContext;//--: check if memory if validatedif (!Validate_User_Memory(UserContext,srcInUser, bufSize))return false;memcpy(destInKernel, UserContext->memory + srcInUser, bufSize);return true;}-----------------------------------------//将内核态的进程复制到用户态bool Copy_To_User(ulong_t destInUser, void* srcInKernel, ulong_t bufSize) {struct User_Context * UserContext = g_currentThread->userContext;if (!Validate_User_Memory(UserContext, destInUser, bufSize))return false;memcpy(UserContext->memory + destInUser, srcInKernel, bufSize);return true;}----------------------------------------//切换到用户地址空间void Switch_To_Address_Space(struct User_Context *userContext){ushort_t ldtSelector= userContext->ldtSelector;/* Switch to the LDT of the new user context */__asm__ __volatile__ ("lldt %0"::"a"(ldtSelector));}================= ===============添加头文件 #include <geekos/>----------------------------------//创建一个用户进程/*static*/ void Setup_User_Thread(struct Kernel_Thread* kthread, struct User_Context* userContext){ulong_t eflags = EFLAGS_IF;unsigned csSelector=userContext->csSelector;//CS选择子unsigned dsSelector=userContext->dsSelector;//DS选择子Attach_User_Context(kthread, userContext);//初始化用户态进程堆栈,使之看上去像刚被中断运行一样//分别调用Push函数将以下数据压入堆栈Push(kthread, dsSelector); //数据选择子Push(kthread, userContext->stackPointerAddr); //堆栈指针Push(kthread, eflags); //EflagsPush(kthread, csSelector); //文本选择子Push(kthread, userContext->entryAddr); //程序计数器Push(kthread, 0); //错误代码(0)Push(kthread, 0); //中断号(0)//初始化通用寄存单元,将ESI用户传递参数块地址Push(kthread, 0); /* eax */Push(kthread, 0); /* ebx */Push(kthread, 0); /* edx */Push(kthread, 0); /* edx */Push(kthread, userContext->argBlockAddr); /* esi */Push(kthread, 0); /* edi */Push(kthread, 0); /* ebp *///初始化数据段寄存单元Push(kthread, dsSelector); /* ds */Push(kthread, dsSelector); /* es */Push(kthread, dsSelector); /* fs */Push(kthread, dsSelector); /* gs */}//开始用户进程struct Kernel_Thread* Start_User_Thread(struct User_Context* userContext, bool detached){struct Kernel_Thread* kthread = Create_Thread(PRIORITY_USER, detached);if (kthread != 0){Setup_User_Thread(kthread, userContext);Make_Runnable_Atomic(kthread);}return kthread;}================ =================//需在此文件别的函数前增加一个函数,函数名为Copy_User_String,它被函数Sys_PrintString调用,具体实现如下:static int Copy_User_String(ulong_t uaddr, ulong_t len, ulong_t maxLen, char**pStr){ int rc = 0;char *str;if (len > maxLen){ //超过最大长度return EINVALID;}str = (char*) Malloc(len+1); //为字符串分配空间if (0 == str){rc = ENOMEM;goto fail;}if (!Copy_From_User(str, uaddr, len)){ //从用户空间中复制数据rc = EINVALID;Free(str);goto fail;}str[len] = '\0';//成功*pStr = str;fail:return rc;}-----------------------------------------static int Sys_Exit(struct Interrupt_State* state){Exit(state->ebx);}-----------------------------------------static int Sys_PrintString(struct Interrupt_State* state){int rc = 0;//返回值uint_t length = state->ecx;//字符串长度uchar_t* buf = 0;if (length > 0) {if ((rc = Copy_User_String(state->ebx, length, 1023, (char**) &buf)) != 0)goto done;Put_Buf(buf, length);}done:if (buf != 0)Free(buf);return rc;}----------------------------------------------static int Sys_GetKey(struct Interrupt_State* state){return Wait_For_Key(); //返回按键码Wait_For_Key()}---------------------------------------------static int Sys_SetAttr(struct Interrupt_State* state){Set_Current_Attr((uchar_t) state->ebx);return 0;}---------------------------------------------static int Sys_GetCursor(struct Interrupt_State* state){int row, col;Get_Cursor(&row, &col);if (!Copy_To_User(state->ebx, &row, sizeof(int)) ||!Copy_To_User(state->ecx, &col, sizeof(int)))return -1;return 0;}-----------------------------------------------static int Sys_PutCursor(struct Interrupt_State* state){return Put_Cursor(state->ebx, state->ecx) 0 : -1;}-----------------------------------------------static int Sys_Spawn(struct Interrupt_State* state){int rc; //函数返回值char *program = 0; //进程名称char *command = 0; //用户命令struct Kernel_Thread *process;if ((rc = Copy_User_String(state->ebx, state->ecx, VFS_MAX_PATH_LEN, &program)) != 0){goto fail;}if(rc = Copy_User_String(state->edx, state->esi, 1023, &command)) != 0) {//从用户空间复制用户命令goto fail;}Enable_Interrupts(); //开中断rc = Spawn(program, command, &process);//得到进程名称和用户命令后便可生成一个新进程if (rc == 0) {//若成功则返回新进程ID号KASSERT(process != 0);rc = process->pid;}Disable_Interrupts();//关中断if (program != 0)Free(program);if (command != 0)Free(command);return rc;}-----------------------------------------static int Sys_Wait(struct Interrupt_State* state){ //TODO("Wait system call");int exitCode;struct Kernel_Thread *kthread = Lookup_Thread(state->ebx);if (kthread == 0)return -12;Enable_Interrupts();exitCode = Join(kthread);Disable_Interrupts();return exitCode;}---------------------------------------static int Sys_GetPID(struct Interrupt_State* state) { //TODO("GetPID system call");return g_currentThread->pid;}================= ================== static void Spawn_Init_Process(void){ //TODO("Spawn the init process");struct Kernel_Thread *pThread;Spawn("/c/","/c/",&pThread);}实验结果如图所示:原理:Geekos 提供了一个简单的shell,保存在PFAT文件系统内,所以geekos系统启动后,启动shell程序/c/运行,将/c/作为可执行文件传递给spawn函数的program参数,创建第一个用户态进程,然后由它来创建其他进程。
实验三P、V 原语的模拟实现实验学时:2实验类型:设计实验要求:必修一、实验目的1) 理解信号量相关理论;2) 掌握记录型信号量结构;3) 掌握P、V 原语实现机制。
二、实验内容本实验针对操作系统中信号量相关理论进行实验,要求学生根据实验指导书提供的代码框架进行实验与测试,可以将所缺代码补充完整,也可以自己重新设计代码框架。
代码主要模拟信号量的P 操作(down)和V 操作(up)。
1) 信号量信号量也称为信号锁,主要应用于进程间的同步和互斥,在用于互斥时,通常作为资源锁。
信号量通常通过两个原子操作down(P)和up(V)来访问。
down 操作使信号量的值+1,up 操作使信号量的值-1。
2) 记录型信号量记录型信号量采用了“让权等待”的策略,由于存在多个进程等待访问同一临界资源的情况,所以记录型信号量需要一个等待链表来存放等待该信号量的进程控制块或进程号。
在本实验中,使用记录型信号量。
三、实验要求1) 完善并添加给定代码;2) 进行功能测试并得出正确结果;3) 分析并在实验报告中画出down 和up 函数流程图;4) 撰写实验报告。
四、实现过程运行过程及结果截图如下:创建进程及信号量:资源信息如下:进程0、1、2、3同时申请资源s1,情况如下:进程4、5、6、7、8同时申请资源s3,情况如下:释放s0资源:再次释放s0:进程8申请资源s2,因为其在阻塞队列中,故无法申请。
如图:进程5也无法申请s2,释放一次s3,进程5就可以申请到s2释放s3四次,进程8可以申请到s4信号量或进程不存在的实例:同一进程在未释放的情况下多次申请同一资源的情况:信号量释放次数超过申请次数的情况:主要代码如下:void down(string name,int pid,pNode *pnode,int pno,signal *sal,int sg) {bool pflag=false;int nodeindex;for(int i=0; i<pno; i++){if(pnode[i].node->pid==pid){pflag=true;nodeindex=i;break;}}if(!pflag){cout<<"进程"<<pid<<"在进程总链中不存在!"<<endl;return;}bool sflag=false;for(int i=0; i<sg; i++){if(sal[i].name==name){if(pnode[nodeindex].block==true){cout<<"该进程现在不能再申请其他资源!"<<endl;return;}if(pnode[nodeindex].flag[i]==true){cout<<"此资源信号量已申请过!"<<endl;return;}sflag=true;sal[i].count--;pnode[nodeindex].flag[i]=true;if(sal[i].count==0){pnode[nodeindex].block=true;sal[i].curpid=pid;cout<<"进程"<<pid<<"申请信号量"<<name<<"已成功!"<<endl;}else if(sal[i].count<0){pnode[nodeindex].block=true;if(sal[i].wHlist==NULL){sal[i].wHlist=&pnode[nodeindex];sal[i].tail=&pnode[nodeindex];}else{sal[i].tail->next=&pnode[nodeindex];sal[i].tail=&pnode[nodeindex];}cout<<"信号量"<<name<<"数量不足,不可用!"<<endl;}return;}}if(!sflag){cout<<"信号量"<<name<<"在信号量数组中不存在!"<<endl;return;}}void up(string name,signal *sal,int sg,pNode *pnode,int sig){bool sflag=false;for(int i=0; i<sg; i++){if(sal[i].name==name){sflag=true;if(sal[i].count==1){cout<<"资源已经满,无需释放!"<<endl;return;}sal[i].count++;if(sal[i].count==1){for(int j=0; j<sig; j++){if(sal[i].curpid==pnode[j].node->pid){pnode[j].flag[i]=false;pnode[j].block=false;break;}}sal[i].curpid=-1;cout<<"信号量释放成功!"<<endl;}else if(sal[i].count<=0){for(int j=0; j<sig; j++){if(sal[i].curpid==pnode[j].node->pid){pnode[j].flag[i]=false;pnode[j].block=false;break;}}pNode *headNode = sal[i].wHlist;sal[i].curpid=sal[i].wHlist->node->pid;sal[i].wHlist=headNode->next;delete headNode;cout<<"释放信号量失败,唤醒队首进程!"<<endl;}return;}}if(!sflag){cout<<"信号量"<<name<<"在信号量数组中不存在!"<<endl;return;}}void showdetail(signal *sal,int sg){for(int i=0; i<sg; i++){cout<<"信号量:"<<sal[i].name<<" 当前的数量为:"<<sal[i].count<<" 当前使用该信号量的进程:"<<sal[i].curpid<<endl;pNode *pnode = sal[i].wHlist;if(pnode == NULL){cout<<"信号量"<<sal[i].name<<"的阻塞队列是空的!"<<endl;}else{while(pnode!=NULL){cout<<pnode->node->pid<<"在"<<sal[i].name<<"的阻塞队列中"<<endl;pnode=pnode->next;}}}}。
操作系统实验2操作系统实验报告哈尔滨工程大学软件学院一、实验概述1. 实验名称实验环境的使用2. 实验目的熟悉操作系统集成实验环境OS Lab的基本使用方法。
练习编译、调试EOS操作系统内核以及EOS应用程序。
3. 实验类型验证二、实验环境OS Lab三、实验过程新建:调试:使用Bochs作为远程目标机:调试:调试软盘引导扇区程序:查看boot.lst文件:查看最后指令字节码调试加载程序:调试内核:EOS启动后的状态和行为:ID是31的是应用程序的进程,ID31的是系统进程。
应用程序的优先级是8,而系统进程的优先级是24,应用程序的进程数是1,而系统进程的进程数是10,并且应用程序是有名字的,而系统程序没有名字。
Id是33的是应用程序的主线程,它与系统线程主要的区别就是优先级不同。
四、思考题1、为什么EOS操作系统从软盘启动时要使用boot.bin和loader.bin两个程序?使用一个可以吗?它们各自的主要功能是什么?如果将loader.bin的功能移动到boot.bin文件中,则boot.bin文件的大小是否仍然能保持小于512字节?答:在IDE环境启动执行EOS操作系统的时候,会把boot.bin、loader.bin和kernel.dll三个二进制文件写到软盘镜像文件中,然后让虚拟机来执行软盘里的EOS操作系统。
仅使用其中的一个是不能运行的。
Boot.bin程序的功能是:在Boot.bin程序执行的过程中,CPU始终处于实模式状态。
Boot.bin程序利用BIOS提供的int 0x13中断服务程序读取软盘FAT12文件系统的根目录,在根目录中搜寻loader.bin文件。
Loader.bin程序的功能是:Loader.bin程序的任务和Boot.bin程序很相似,同样是将其它的程序加载到物理内存中,但这次加载的是EOS内核。
除此之外,Loader.bin程序还负责检测内存大小,为内核准备保护模式执行环境等工作。
西北工业大学操作系统实验实验报告一、实验目的熟悉GeekOS实验环境。
二、实验要求编译运行操作系统的启动代码。
三、实验过程及结果1、编写第一个“操作系统”,代码如下:org 07c00hmov ax,csmov ds,axmov es,axcall DispStrjmp $DispStr:mov ax,BootMessagemov bp,axmov cx,16mov ax,01301hmov bx,00aehmov dl,0int 10hretBootMessage: db "hello,OS world!"times 510-($-$$) db 0dw 0xaa55结果如图:修改boot.asm,修改文字颜色,代码如下:org 07c00hmov ax,csmov ds,axmov es,axcall DispStrjmp $DispStr:mov ax,BootMessagemov bp,axmov cx,16mov ax,01301hmov bx,00aeh //在此处修改BL的值,可以修改颜色mov dl,0int 10hretBootMessage: db "hello,OS world! "times 510-($-$$) db 0dw 0xaa55结果如图:2.在bochs中运行geek OS,结果如图:四、实验分析思考:引导扇区的标志是0x55AA,为何代码中写入的却是 dw 0xAA55?答:因为存储时低位在前,高位在后,所以代码中高低位反过来写。
五、所遇问题及解决方法答:实验过程中,最大的困难就是理解geek OS的代码。
一个原因是我们没有学过有关汇编的知识,导致代码中有关汇编的部分一头雾水,难以理解;另一方面是之前自己接触的源码比较少,第一次见到geek OS这么大的工程代码,感觉理解起来很困难,不过,在老师花费了几个小时的讲解下,我最终还是勉强理解了一部分。
计算机系统基础实验课第二次实验报告对二进制炸弹求解过程的详细描述首先使用objdump命令对bomb程序进行反汇编,并将汇编代码输出到asm.txt中。
阶段一、字符串比较打开asm.txt文件,搜索到phase_1函数,可以看到以下代码。
08048b33 <phase_1>:8048b33: 83 ec 14 sub $0x14,%esp8048b36: 68 7c a0 04 08 push $0x804a07c8048b3b: ff 74 24 1c pushl 0x1c(%esp)8048b3f: e8 3e 05 00 00 call 8049082 <strings_not_equal>8048b44: 83 c4 10 add $0x10,%esp8048b47: 85 c0 test %eax,%eax8048b49: 74 05 je 8048b50 <phase_1+0x1d>8048b4b: e8 29 06 00 00 call 8049179 <explode_bomb>8048b50: 83 c4 0c add $0xc,%esp8048b53: c3 ret可以看出,用户输入字串指针保存在0x1c(%esp),然后调用<strings_not_equal>,待<strings_not_equal>返回后,测试返回值,若equal则进入下一phase,否则<explode_bomb>,从<strings_not_equal>可知该函数用于比较两函数的值,因此需要两个字串作为输入,上面代码中, pushl 0x1c(%esp)用于传递用户字串指针,则push $0x804a07c自然是传递比较字串的指针了。
打开gdb,x/s 0x80497c0, 可以直接查看到该指针指向的子符串:所以第一个炸弹的拆弹指令为:I turned the moon into something I call a Death Star.阶段二、循环在asm.txt文件中可以找到phase_2函数代码如下:08048b54 <phase_2>:8048b54: 56 push %esi8048b55: 53 push %ebx8048b56: 83 ec 2c sub $0x2c,%esp8048b59: 65 a1 14 00 00 00 mov %gs:0x14,%eax8048b5f: 89 44 24 24 mov %eax,0x24(%esp)8048b63: 31 c0 xor %eax,%eax8048b65: 8d 44 24 0c lea 0xc(%esp),%eax8048b69: 50 push %eax8048b6a: ff 74 24 3c pushl 0x3c(%esp)8048b6e: e8 2b 06 00 00 call 804919e <read_six_numbers>8048b73: 83 c4 10 add $0x10,%esp8048b76: 83 7c 24 04 01 cmpl $0x1,0x4(%esp)8048b7b: 74 05 je 8048b82 <phase_2+0x2e>8048b7d: e8 f7 05 00 00 call 8049179 <explode_bomb>8048b82: 8d 5c 24 04 lea 0x4(%esp),%ebx8048b86: 8d 74 24 18 lea 0x18(%esp),%esi8048b8a: 8b 03 mov (%ebx),%eax8048b8c: 01 c0 add %eax,%eax8048b8e: 39 43 04 cmp %eax,0x4(%ebx)8048b91: 74 05 je 8048b98 <phase_2+0x44>8048b93: e8 e1 05 00 00 call 8049179 <explode_bomb>8048b98: 83 c3 04 add $0x4,%ebx8048b9b: 39 f3 cmp %esi,%ebx8048b9d: 75 eb jne 8048b8a <phase_2+0x36>8048b9f: 8b 44 24 1c mov 0x1c(%esp),%eax8048ba3: 65 33 05 14 00 00 00 xor %gs:0x14,%eax8048baa: 74 05 je 8048bb1 <phase_2+0x5d>8048bac: e8 df fb ff ff call 8048790 <__stack_chk_fail@plt>8048bb1: 83 c4 24 add $0x24,%esp8048bb4: 5b pop %ebx8048bb5: 5e pop %esi8048bb6: c3 ret根据call 804919e <read_six_numbers>可以推测题目要求是输入六个数字。
北航os实验报告北航OS实验报告一、引言操作系统(Operating System,简称OS)是计算机系统中最基础的软件之一,它负责管理和控制计算机硬件资源,为用户和应用程序提供一个可靠、高效的工作环境。
本文将对北航OS实验进行详细的报告和分析。
二、实验目的本次北航OS实验的目的是让学生深入理解和掌握操作系统的基本原理和实现方式。
通过实践,学生将学会设计和实现一个简单的操作系统,了解操作系统的核心功能和运行机制。
三、实验内容1. 系统引导实验开始时,我们需要编写引导程序,将操作系统加载到计算机的内存中,并跳转到操作系统的入口地址开始执行。
这一步骤是整个实验的起点,也是操作系统正常运行的基础。
2. 中断处理操作系统需要能够处理各种中断事件,如时钟中断、键盘中断等。
学生需要实现中断处理程序,使操作系统能够响应和处理这些中断事件,并根据具体情况进行相应的操作。
3. 进程管理操作系统需要能够管理多个进程的创建、调度和终止。
学生需要设计并实现进程管理模块,包括进程控制块(PCB)的数据结构和进程调度算法。
通过合理的调度策略,提高系统的并发性和响应速度。
4. 内存管理操作系统需要管理计算机的内存资源,包括内存的分配和释放。
学生需要设计并实现内存管理模块,使用合适的算法来管理内存的分配和回收,避免内存泄漏和碎片化问题。
5. 文件系统操作系统需要提供文件系统来管理计算机中的文件和数据。
学生需要设计并实现一个简单的文件系统,包括文件的创建、读写和删除等操作。
通过文件系统,用户可以方便地存储和管理自己的数据。
四、实验过程在实验过程中,我们遇到了许多挑战和问题,但通过不断的尝试和调试,我们最终成功实现了一个简单的操作系统。
以下是我们在实验过程中遇到的一些关键问题和解决方案:1. 内存管理在实验过程中,我们发现内存管理是一个非常关键的问题。
如果内存管理不当,容易导致内存泄漏或者内存碎片化,从而影响系统的性能和稳定性。
我们通过设计一个位图来管理内存的分配和释放,使用首次适应算法来分配内存,并通过合理地回收内存来避免内存泄漏问题。
北航ARM9嵌⼊式系统实验实验三uCOS-II实验实验三 uCOS-II实验⼀、实验⽬的在内核移植了uCOS-II 的处理器上创建任务。
⼆、实验内容1)运⾏实验⼗,在超级终端上观察四个任务的切换。
2)任务1~3,每个控制“红”、“绿”、“蓝”⼀种颜⾊的显⽰,适当增加OSTimeDly()的时间,且优先级⾼的任务延时时间加长,以便看清三种颜⾊。
3)引⼊⼀个全局变量BOOLEAN ac_key,解决完整刷屏问题。
4)任务4管理键盘和超级终端,当键盘有输⼊时在超级终端上显⽰相应的字符。
三、预备知识1)掌握在EWARM 集成开发环境中编写和调试程序的基本过程。
2)了解ARM920T 处理器的结构。
3)了解uCOS-II 系统结构。
四、实验设备及⼯具1)2410s教学实验箱2)ARM ADS1.2集成开发环境3)⽤于ARM920T的JTAG仿真器4)串⼝连接线五、实验原理及说明所谓移植,指的是⼀个操作系统可以在某个微处理器或者微控制器上运⾏。
虽然uCOS-II的⼤部分源代码是⽤C语⾔写成的,仍需要⽤C语⾔和汇编语⾔完成⼀些与处理器相关的代码。
⽐如:uCOS-II在读写处理器、寄存器时只能通过汇编语⾔来实现。
因为uCOS-II 在设计的时候就已经充分考虑了可移植性,所以,uCOS-II的移植还是⽐较容易的。
要使uCOS-II可以正常⼯作,处理器必须满⾜以下要求:(1)处理器的C编译器能产⽣可重⼊代码可重⼊的代码指的是⼀段代码(如⼀个函数)可以被多个任务同时调⽤,⽽不必担⼼会破坏数据。
也就是说,可重⼊型函数在任何时候都可以被中断执⾏,过⼀段时间以后⼜可以继续运⾏,⽽不会因为在函数中断的时候被其他的任务重新调⽤,影响函数中的数据。
(2)在程序中可以打开或者关闭中断在uCOS-II中,可以通过OS_ENTER_CRITICAL()或者OS_EXIT_CRITICAL()宏来控制系统关闭或者打开中断。
这需要处理器的⽀持,在ARM920T的处理器上,可以设置相应的寄存器来关闭或者打开系统的所有中断。
实验五进程管理一、实验目的(1)加深对进程概念的理解,明确进程和程序的区别;(2)进一步认识并发执行的实质;(3)了解FreeBSD系统中进程通信的基本原理。
二、实验内容与要求1、掌握进程的概念,明确进程的含义;2、编写一段程序,使用系统调用fork( )创建两个子进程。
当此程序运行时,在系统中有一个父进程和两个子进程活动。
让每一个进程在屏幕上显示一个字符:父进程显示'a',子进程分别显示字符'b'和字符'c'。
试观察记录屏幕上的显示结果(多次运行,查看结果是否有变化),并分析原因;3、修改已编写的程序,将每个进程输出一个字符改为每个进程输出一句话,在观察程序执行时屏幕出现的现象(多次运行,查看结果是否有变化),并分析原因;4、如果在程序中使用调用lockf()来给每一个子进程加锁,可以实现进程之间的互斥,观察并分析出现的现象;5、对整个实验过程进行分析总结,给出详细步骤;三、实验过程1、进程的概念与含义狭义:进程就是一段程序的执行过程。
广义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。
它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。
进程的概念主要有两点:第一,进程是一个实体。
每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。
文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。
第二,进程是一个“执行中的程序”。
程序是一个没有生命的实体,只有处理器赋予程序生命时,它才能成为一个活动的实体,我们称其为进程。
进程是操作系统中最基本、重要的概念。
是多道程序系统出现后,为了刻画系统内部出现的动态情况,描述系统内部各道程序的活动规律引进的一个概念,所有多道程序设计操作系统都建立在进程的基础上。
《操作系统》实验教学大纲实验名称:操作系统实验实验课程:计算机科学与技术、软件工程、电子信息工程实验学时:24学时(12次课程实验)实验目的:1.通过操作系统实验,学生将深入了解操作系统的原理和设计。
2.学生将掌握操作系统的基本概念和常用技术。
3.提高学生的实践能力和创新能力,培养学生的团队合作精神。
实验内容:1.实验一:操作系统基本概念-实验介绍:了解操作系统的基本概念和基本功能。
-实验要求:学生通过阅读文献或参考书籍,掌握操作系统的基本概念。
-实验过程:学生通过讨论或小组讨论的方式,给出操作系统的定义和基本功能列表。
2.实验二:进程管理-实验介绍:通过实验来学习进程管理的基本概念和常用算法。
-实验要求:学生通过自己编写程序,实现进程的创建、销毁和调度。
-实验过程:学生根据给定的问题,设计进程模型并实现相应的程序。
3.实验三:内存管理-实验介绍:了解内存管理的基本概念和常用算法,学习虚拟内存技术的原理。
-实验要求:学生通过编写程序,实现内存分配和回收的算法。
-实验过程:学生通过模拟内存分配和回收的过程,理解内存管理的基本原理。
4.实验四:文件系统-实验介绍:了解文件系统的基本概念和常用算法,学习文件管理的基本原理。
-实验要求:学生通过编写程序,实现文件的创建、删除和查找。
-实验过程:学生通过模拟文件的创建、删除和查找的过程,理解文件管理的基本原理。
5.实验五:设备管理-实验介绍:通过实验学习设备管理的基本概念和常用算法,了解设备驱动程序的实现原理。
-实验要求:学生通过编写程序,模拟设备的控制和管理。
-实验过程:学生通过模拟设备的请求、分配和释放的过程,理解设备管理的基本原理。
6.实验六:作业调度-实验介绍:通过实验学习作业调度的基本概念和常用算法。
-实验要求:学生通过编写程序,实现作业的调度。
-实验过程:学生通过输入作业和作业调度算法,模拟作业调度的过程。
实验评定:-实验报告:60%-实验成果:20%-实验操作:20%实验环境:- 操作系统:Linux、Windows实验要求:-学生需认真完成实验任务,编写实验报告。
陕西国防工业职业技术学院
实训报告
姓名:
学号:
指导老师:
实验时间:2012.6
实验地点:网络实验室
成绩:
计算机教研室制
陕西国防工业职业技术学院SHAANXIINSTITUTE OF TECHNOLOGY
实验项目单
配置OU
2、DHCP服务器
3、DNS服务器的配置和管理
4、Wins服务器的配置和管理
5、管理IIS 6
6、VPN服务,远程服务
实训总结
通过周对windows server2003的学习,让我有了更多一些了解。
在这周的第一天老师首先该我们就讲了一些关于windows server2003中有关DNS、DHCP、IIS 6、WINS、VPN服务器的一些知识,
在后来的是几天时间里,老师又让我们做了活动目录的安装、利用DHCP服务器自动分配IP地址(将虚拟机的网卡类型设置成host-only)、DNS服务器的配置和管理、Wins服务器的配置和管理、管理IIS 6、VPN服务,远程服务的一些实验。
在学习windows server2003时,我们也学习到了相关方面很多知识。
以及一系列的相关知识的学习,我们也学会了这一次实训中的知识,结合这老师给的语句我么也可以自己做下来。
所以这周的实训觉得自己的收获来是挺多的。
以后也会努力的。
评语: 课中检查完成的题号及题数:课后完成的题号与题数:成绩: 指导教师:实验报告三实验名称:实验七理解线程的相关概念日期:2013.5.23班级:10011007 学号:2010302539 姓名:严园一、实验目的:1.理解当操作系统引入线程的概念后,进程是操作系统独立分配资源的单位,线程成为系统调度的单位,与同一个进程中的其他线程共享程序空间。
二、实验内容:1. (1)编写一个程序,在其main()函数中创建一个(或多个)线程,观察该线程是如何与主线程并发运行的。
输出每次操作后的结果;(2)在main()函数外定义一个变量shared(全局变量),在main()中创建一个线程,在main()中和新线程shared 进行循环加/减操作,观察该变量的变化;(3)修改程序把shared 变量定义到main()函数之内,重复第(2)步操作,观察该变量的变化。
三、项目要求及分析:1. 预习线程创建和构造的相关知识,了解C语言程序编写的相关知识。
编写一个程序,在其main()函数中创建一个(或多个)线程,观察该线程是如何与主线程并发运行的。
输出每次操作后的结果;分别在main()函数内和函数外定义一个变量shared(全局变量),在main()中创建一个线程,在main()中和新线程shared 进行循环加/减操作,观察该变量的变化。
四、具体实现:4.1 流程图4.2 添加函数的代码(1)程序开始设置shared为全局变量或局部变量创建主线程创建子线程主线程sleep 1sShared是全局变量子线程对shared操作并输出结果主线程对shared操作并输出结果程序结束全局变量?shared不是全局变量子线程对shared地址操作(2)Shared为局部变量(传shared的值)(3)Shared为局部变量(传shared的地址):五、调试运行结果:(1)(2)(3)六、所遇问题及解决方法:在实验开始的时候,不清楚线程的创建以及工作机制,导致在实验中对线程创建部分总有错误,后来经过和班级同学的交流以及查阅相关资料,才对线程的构建有所理解,并最终正确的完成实验要求。
七、实验总结:1.在理解线程的相关概念的实验中,应注意shared 的全局性和局部性,而且在作为全局变量时,主线程和子线程可以对它进行同步操作,子线程只是主线程的一部分,二者共享线程所分有的地址空间以及其他共有信息。
2.在shared作为局部变量的试验中,pthread_create的最后一个参数可以传递shared的地址,此时shared相当于共有变量,也可以传递shared的值,此时二者对shared 的操作互不影响,shared相当于各个线程中的私有变量。
实验名称:实验八请求分页存储管理设计日期:2013.5.23班级:10011007 学号:2010302539 姓名:严园一、实验目的:1.模拟存储管理常用的请求分页存储管理技术,通过本实验使学生更加深入的理解虚拟内存的思想和主要的页面淘汰算法。
二、实验内容:1. (1) 通过随机数产生一个指令行列,共320条指令,指令中的地址按下述原则生成:50%的指令是顺序执行;25%的指令均匀分布在前地址部分;25%的指令均匀分布在后地址部分。
(2) 具体实验办法是:在[0,319]之间选一起始点M;顺序执行一条指令,即第M+1条;向前地址[0,M-1]中执行一条指令M;顺序执行一条指令,即第M+1条;向后地址[M+2,319]中执行一条指令M。
如此继续,直至产生320条指令。
使用产生随机数的函数之前,首先要初始化设置RAN()产生序列的开始点,SRAND(400);然后计算随机数,产生指令序列。
例如:a[0]=1.0*rand()/32767*319+1;a[1]=a[0]+1;a[2]=1.0*rand()/32767*(a[1]-1)+1;a[3]=a[2]+1;a[4]=319-1.0*rand()/32767*(a[3]-1);其中rand()和srand()为Linux操作系统提供的函数分别进行初始化和产生随机数,多次重复使用这5条指令,产生以后的指令序列。
(3) 将指令序列变换成页面地址流:假设,页面大小为1KB;用户实存容量(内存区容量)为4页或32页;用户虚存容量(逻辑地址空间容量)为32KB;用户虚存容量32KB,每1KB中放10条指令,共320条指令序列,按其地址0~9在0页,10~19在1页,…….,310~319在31页。
(4) 使用不同的页面调度算法处理缺页中断,并计算不同实存容量下的命中率:先进先出(FIFO)算法;最近最少使用(LRU)算法;命中率的算法为:命中率= 1 - (缺页中断次数/页地址流长度)。
本实验中,页地址流长度为320,缺页中断次数为每次访问相应指令时,该指令所对应的页不在内存的次数。
三、项目要求及分析:1. 学习虚拟存储器的相关基础知识,了解请求分页存储管理系统的原理和具体实现过程,熟悉各种主要的页面调度算法。
通过实验指导书的参考,编写LRU和FIFO算法程序,观察调度过程。
四、具体实现:4.1 流程图程序开始按要求产生页面流使用FIFO算法进行替换使用LRU算法进行替换输出统计结果信息程序结束4.2 添加函数的代码#include <stdio.h>#include <stdlib.h>#include <time.h>#define NYEMIAN 320 //页面流长度320#define NZHAN 5 //FIFO,LRU所使用的栈长度,或队列长度,NZHAN-1,数值为5或33,要特别注意!!!!!int mem[NZHAN]={-1,-1,-1,-1,-1}; //初始化栈或队列int Out[NYEMIAN]; //记录每次调出的界面int In[NYEMIAN]; //记录每次调入的界面/*********************************************************//******************* 用于格式输出算法*********************//*********************************************************/void Output(int array[],int Length,int flag){int i=0;for(i=0;i<Length-flag;i++){switch(array[i]){case -1:printf("%2c ",35);break;case -2:printf("%2c \n",32);break;case -3:printf("%2c \n",42);break;default:printf("%2d ",array[i]);break;}}printf("\n");}/*********************************************************//********************** FIFO算法***************************//*********************************************************/void creatFifo(int array[NYEMIAN]) //FIFO替换函数{int i,j,t=0,t1=0,temp,flag=0;for(i=0;i<NYEMIAN;i++){Out[i]=-1;In[i]=-1;}for(i=0;i<NYEMIAN;i++) //查页表,看是否缺页,FIFO {j=0;while((array[i]!=mem[j])&&(j<NZHAN-1))j++;if(j==NZHAN-1){temp=0;Out[t]=mem[temp]; //记录此次调出的界面t++;while(temp!=NZHAN-1){mem[temp]=mem[temp+1];temp++;}if(temp==NZHAN-1){mem[temp-1]=array[i];In[t1]=array[i]; //记录此次调入界面t1++;}mem[temp]=-2; //没有命中}else{mem[NZHAN-1]=-3;//命中了flag=flag+1;}/*此处可以显示调入调出的栈内内容的变换过程*//* Output(mem,NZHAN,0);*/}printf("移出的页面为:");Output(Out,NYEMIAN,flag); //显示移出的界面printf("移入的页面为:");Output(In,NYEMIAN,flag); //显示移进的界面printf("最后一次替换后主存中的页面号:");Output(mem,NZHAN,0); //显示最后一次替换后主存中的页面号printf("FIFO命中次数为%d,命中率为:%lf\n",flag,(double)flag/NYEMIAN);}/*********************************************************//********************** LRU算法***************************//*********************************************************/void createLru(int array[NYEMIAN]) //LRU替换函数{int i,j,t=0,t1=0,temp,flag=0;for(i=0;i<NZHAN;i++)mem[i]=-1;for(i=0;i<NYEMIAN;i++){Out[i]=-1;In[i]=-1;}for(i=0;i<NYEMIAN;i++) //查页表,看是否缺页,LRU{j=0;while((array[i]!=mem[j])&&(j<NZHAN-1))j++;if(j==NZHAN-1){temp=0;Out[t]=mem[temp]; //记录此时移除的界面t++;while(temp!=NZHAN-1){mem[temp]=mem[temp+1];temp++;}if(temp==NZHAN-1){mem[temp-1]=array[i];In[t1]=array[i]; //记录此时移入的界面t1++;}mem[temp]=-2;//没有命中}else{mem[NZHAN-1]=-3;//命中了flag=flag+1;temp=mem[j]; //记录命中位置 while(j!=NZHAN-1){mem[j]=mem[j+1];j++;}if(j==NZHAN-1) //移动到最后位置 {mem[NZHAN-2]=temp;}}/*此处可以显示调入调出的栈内内容的变换过程*//*Output(mem,NZHAN,0);*/}printf("移出的页面为:");Output(Out,NYEMIAN,flag); //显示移出的界面printf("移入的页面为:");Output(In,NYEMIAN,flag); //显示移进的界面printf("最后一次替换后主存中的页面号:");Output(mem,NZHAN,0); //显示最后一次替换后主存中的页面号printf("LRU命中次数为%d,命中率为:%lf\n",flag,(double)flag/NYEMIAN);}int main(){int i;int a[NYEMIAN];/*随机产生的页面流,其中共320条指令,指令中的地址按下述原则生成:50%的指令是顺序执行;25%的指令均匀分布在前地址部分;25%的指令均匀分布在后地址部分。