操作系统第三次实验报告
- 格式:doc
- 大小:589.50 KB
- 文档页数:9
操作系统实验报告3一、实验目的本次操作系统实验的主要目的是深入了解和掌握操作系统中进程管理、内存管理以及文件系统等核心概念和相关技术,并通过实际的实验操作,提高对操作系统原理的理解和应用能力。
二、实验环境本次实验使用的操作系统为 Windows 10,开发工具为 Visual Studio 2019。
三、实验内容及步骤(一)进程管理实验1、创建进程使用 C++语言编写程序,通过调用 Windows API 函数`CreateProcess`来创建一个新的进程。
在创建进程时,设置进程的优先级、环境变量等参数,并观察进程的创建过程和相关的系统资源使用情况。
```cppinclude <windowsh>include <iostream>int main(){STARTUPINFO si;PROCESS_INFORMATION pi;ZeroMemory(&si, sizeof(si));sicb = sizeof(si);ZeroMemory(&pi, sizeof(pi));//设置进程的优先级为 HIGH_PRIORITY_CLASS DWORD priorityClass = HIGH_PRIORITY_CLASS;//创建进程if (!CreateProcess(NULL, //应用程序名称"notepadexe",//命令行参数NULL, //进程安全性NULL, //线程安全性FALSE, //不继承句柄priorityClass, //进程优先级NULL, //环境变量NULL, //当前目录&si,&pi)){std::cout <<"CreateProcess failed Error code: "<<GetLastError()<< std::endl;return 1;}//等待进程结束WaitForSingleObject(pihProcess, INFINITE);//关闭进程和线程的句柄CloseHandle(pihProcess);CloseHandle(pihThread);return 0;}```2、进程同步与互斥编写一个多线程程序,模拟生产者消费者问题。
操作系统实验报告三一、实验目的本次实验的目的是通过设计和实现一个简单的操作系统,加深对操作系统内核设计的理解,并学习操作系统内核的基本构建和运行原理。
二、实验背景操作系统是计算机系统中最核心的软件之一,它负责管理计算机的各种资源以及协调和控制应用程序的执行。
操作系统的设计和实现使计算机能够高效地运行并提供友好的用户接口。
操作系统也为应用程序提供了统一的软硬件访问接口,方便开发人员进行软件开发。
操作系统的设计和实现是计算机科学与技术领域中重要的研究方向之一。
通过操作系统的实验,可以深入了解操作系统的内部原理和机制,加深对操作系统的理解和认识。
三、实验内容本次实验需要设计和实现一个简单的操作系统,完成以下功能:1. 实现一个简单的内存管理模块,包括内存分配和释放的功能。
2. 实现一个简单的进程管理模块,包括进程的创建、撤销和切换的功能。
3. 实现一个简单的文件系统模块,包括文件的读写和目录的管理功能。
4. 实现用户与操作系统之间的交互界面,方便用户进行操作系统的使用。
四、实验步骤1. 设计和实现内存管理模块:a. 设计内存分配算法,根据系统的需要分配和释放内存空间。
b. 实现内存分配和释放的功能函数,确保能够正确地分配和释放内存空间。
2. 设计和实现进程管理模块:a. 设计进程控制块(PCB),记录进程的相关信息。
b. 实现进程的创建、撤销和切换的功能函数,确保进程能够正确地被创建、撤销和切换。
3. 设计和实现文件系统模块:a. 设计文件控制块(FCB),记录文件的相关信息。
b. 实现文件的读写和目录的管理功能函数,确保文件能够正确地被读写和目录能够正确地被管理。
4. 实现用户与操作系统之间的交互界面:a. 设计用户界面,包括命令解释器等。
b. 实现用户输入命令的解释和执行函数,确保用户能够正确地与操作系统进行交互。
五、实验结果与分析经过实验,我们成功地设计和实现了一个简单的操作系统,并完成了内存管理、进程管理和文件系统的功能实现。
向kernel/printk.c中添加日志打印功能,将以下代码添加到原文件中:
在kernel/fork.c、kernel/sched.c和kernel/exit.c中,找到正确的状态转换点,并添加合适的状态信息,把它输出到log文件之中。
fork.c的修改如下:
exit.c的修改如下:
sched.c的修改如下:
在虚拟机上运行ls -l /var”或“ll /var”查看process.log是否建立,及它的属性和长度;
修改时间片
include/linux/sched.h宏INIT_TASK中定义的:
0,15,15, 分别对应state、counter和priority,将priority值修改,即可实现对时间片大小的调整。
0,15,15, 分别对应state、counter和priority,
priority值修改,即可实现对时间片大小的调整。
在修改时间片将priority由15改为150后,Process 9~20 中Turnaround, Waiting, CPU Burst, I/O Burst变化不大,原因可能是程序中I/O操作占用的时间对于总时间影响的权重过大,导致处理时间体现的并不明显。
或者变化不大的原因是,子进程连续占用cpu的时间要比时间片大很多。
《操作系统》实验报告
实验序号:3 实验项目名称:作业调度的实现
return 0;
}
具体实现步骤:
1.将实验指导目录中linux下的os3中的src 放在桌面上。
2.打开终端1,输入以下指令:
【cd ./桌面/src】
【gcc job.c error.c –ojob】
【gcc enq.c error.c -oenq】
【gcc deq.c error.c -odeq】
【gcc stat.c error.c -ostat】
3.编写123.c和456.c两个死循环程序,编译运行无误,并改名生成程序P1,
P2。
4.执行./job &指令将p2添加到p1中。
5.打开终端2
输入【cd ./桌面/src】指令
执行【./stat】指令查看进程状态
反复调用【./stat】指令
6.交替执行指令【./enq】和【./deq】指令删除p1,p2并再次添加并调用【./stat】
指令查看进程变化。
7.实验完成后调用【kill】指令结束进程。
运行截图如下:。
实验三实验报告实验源码:#include "stdio.h"#include <iostream.h>#include <stdlib.h>#define DataMax 100 // 常量DataMax#define BlockNum 10 // 常量BlockNumint DataShow[BlockNum][DataMax]; // 用于存储要显示的数组bool DataShowEnable[BlockNum][DataMax]; // 用于存储数组中的数据是否需要显示int Data[DataMax]; // 保存数据int Block[BlockNum]; // 物理块int count[BlockNum]; // 计数器int N; // 页面个数int M; // 最小物理块数int ChangeTimes; // 缺页次数void DataInput(); // 输入数据的函数void DataOutput(); // 输出数据的函数void FIFO(); // FIFO 函数void Optimal(); // Optimal函数void LRU(); // LRU函数int main(int argc, char* argv[]){DataInput();int menu;while(true){printf("\n* 菜单选择*\n");printf("*******************************************************\n");printf("* 1-Optimal *\n");printf("* 2-FIFO *\n");printf("* 3-LRU *\n");printf("* 4-返回上一级*\n");printf("* 0-EXIT *\n");printf("*******************************************************\n");scanf("%d",&menu);switch(menu){case 1:Optimal();break;case 2:FIFO();break;case 3:LRU();break;case 0:exit(0);break;case 4:system("cls");DataInput();break;}if(menu != 1 && menu != 2 && menu != 3 && menu != 0 && menu !=4) { system("cls");printf("\n请输入0 - 4之间的整数!\n");continue;}}return 0;}void DataInput(){int i,choice;printf("请输入最小物理块数:");scanf("%d",&M);// 输入最小物理块数大于数据个数while(M > BlockNum){printf("物理块数超过预定值,请重新输入:");scanf("%d",&M);}printf("请输入页面的个数:");scanf("%d",&N);// 输入页面的个数大于数据个数while(N > DataMax){printf("页面个数超过预定值,请重新输入:");scanf("%d",&N);}printf("请选择产生页面访问序列的方式(1.随机2.输入):");scanf("%d",&choice);switch(choice){case 1:// 产生随机访问序列for(i = 0;i < N;i++){Data[i] = (int)(((float) rand() / 32767) * 10); // 随机数大小在0 - 9之间}system("cls");// 显示随机产生的访问序列printf("\n随机产生的访问序列为:");for(i = 0;i < N;i++){printf("%d ",Data[i]);}printf("\n");break;case 2:// 输入访问序列printf("请输入页面访问序列:\n");for(i = 0;i < N;i++)scanf("%d",&Data[i]);system("cls");// 显示输入的访问序列printf("\n输入的访问序列为:");for(i = 0;i < N;i++){printf("%d ",Data[i]);}printf("\n");break;default:while(choice != 1 && choice != 2){printf("请输入1或2选择相应方式:");scanf("%d",&choice);}break;}}void DataOutput(){int i,j;// 对所有数据操作for(i = 0;i < N;i++){printf("%d ",Data[i]);}printf("\n");for(j = 0;j < M;j++){// 对所有数据操作for(i = 0;i < N;i++){if( DataShowEnable[j][i] )printf("%d ",DataShow[j][i]);elseprintf(" ");}printf("\n");}printf("缺页次数: %d\n",ChangeTimes);printf("缺页率: %d %%\n",ChangeTimes * 100 / N); }// 最佳置换算法void Optimal(){int i,j,k;bool find;int point;int temp; // 临时变量,比较离的最远的时候用int m = 1,n;ChangeTimes = 0;for(j = 0;j < M;j++){for(i=0;i < N;i++){DataShowEnable[j][i] = false; // 初始化为false,表示没有要显示的数据}}for(i = 0;i < M;i++){count[i] = 0 ; // 初始化计数器}// 确定当前页面是否在物理块中,在继续,不在置换/////////////////////////////////////////////////////////////////////////////////// Block[0] = Data[0];for(i = 1;m < M;i++){int flag = 1;for(n = 0; n < m;n++){if(Data[i] == Block[n]) flag = 0;}if(flag == 0) continue;Block[m] = Data[i];m++;}//////////////////////////////////////////////////////////////////////////////////// 对所有数据进行操作for(i=0;i < N;i++){// 表示块中有没有该数据find = false;for(j = 0;j < M;j++){if( Block[j] == Data[i] ){find = true;}}if( find ) continue; // 块中有该数据,判断下一个数据// 块中没有该数据,最优算法ChangeTimes++; // 缺页次数++for(j = 0;j < M;j++){// 找到下一个值的位置find = false;for( k = i;k < N;k++){if( Block[j] == Data[k] ){find = true;count[j] = k;break;}}if( !find ) count[j] = N;}// 因为i是从0开始记,而BlockNum指的是个数,从1开始,所以i+1if( (i + 1) > M ){//获得要替换的块指针temp = 0;for(j = 0;j < M;j++){if( temp < count[j] ){temp = count[j];point = j; // 获得离的最远的指针}}}else point = i;// 替换Block[point] = Data[i];// 保存要显示的数据for(j = 0;j < M;j++){DataShow[j][i] = Block[j];DataShowEnable[i < M ? (j <= i ? j : i) : j][i] = true; // 设置显示数据}}// 输出信息printf("\nOptimal => \n");DataOutput();}// 先进先出置换算法void FIFO(){bool find;int point;int temp; // 临时变量int m = 1,n;ChangeTimes = 0;for(j = 0;j < M;j++){for(i = 0;i < N;i++){DataShowEnable[j][i] = false; // 初始化为false,表示没有要显示的数据}}for(i = 0;i < M;i++){count[i] = 0; // 大于等于BlockNum,表示块中没有数据,或需被替换掉// 所以经这样初始化(3 2 1),每次替换>=3的块,替换后计数值置1,// 同时其它的块计数值加1 ,成了(1 3 2 ),见下面先进先出程序段}// 确定当前页面是否在物理块中,在继续,不在置换/////////////////////////////////////////////////////////////////////////////////// Block[0] = Data[0];for(i = 1;m < M;i++){int flag = 1;for(n = 0; n < m;n++){if(Data[i] == Block[n]) flag = 0;}if(flag == 0) continue;Block[m] = Data[i];m++;}//////////////////////////////////////////////////////////////////////////////////// 对有所数据操作for(i = 0;i < N;i++){// 增加countfor(j = 0;j < M;j++){count[j]++;find = false; // 表示块中有没有该数据for(j = 0;j < M;j++){if( Block[j] == Data[i] ){find = true;}}// 块中有该数据,判断下一个数据if( find ) continue;// 块中没有该数据ChangeTimes++; // 缺页次数++// 因为i是从0开始记,而M指的是个数,从1开始,所以i+1if( (i + 1) > M ){//获得要替换的块指针temp = 0;for(j = 0;j < M;j++){if( temp < count[j] ){temp = count[j];point = j; // 获得离的最远的指针}}}else point = i;// 替换Block[point] = Data[i];count[point] = 0; // 更新计数值// 保存要显示的数据for(j = 0;j < M;j++){DataShow[j][i] = Block[j];DataShowEnable[i < M ? (j <= i ? j : i) : j][i] = true; // 设置显示数据}}// 输出信息printf("\nFIFO => \n");DataOutput();}// 最近最久未使用置换算法void LRU(){int i,j;bool find;int point;int temp; // 临时变量int m = 1,n;ChangeTimes = 0;for(j = 0;j < M;j++){for(i = 0;i < N;i++){DataShowEnable[j][i] = false; // 初始化为false,表示没有要显示的数据}}for(i = 0;i < M;i++){count[i] = 0 ; // 初始化计数器}// 确定当前页面是否在物理块中,在继续,不在置换///////////////////////////////////////////////////////////////////////////////////Block[0] = Data[0];for(i = 1;m < M;i++){int flag = 1;for(n = 0; n < m;n++){if(Data[i] == Block[n]) flag = 0;}if(flag == 0) continue;Block[m] = Data[i];m++;}//////////////////////////////////////////////////////////////////////////////////// 对有所数据操作for(i = 0;i < N;i++){// 增加countfor(j = 0;j < M;j++){count[j]++;}find = false; // 表示块中有没有该数据for(j = 0;j < M;j++){if( Block[j] == Data[i] ){count[j] = 0;find = true;}}// 块中有该数据,判断下一个数据if( find ) continue;// 块中没有该数据ChangeTimes++;// 因为i是从0开始记,而BlockNum指的是个数,从1开始,所以i+1 if( (i + 1) > M ){//获得要替换的块指针temp = 0;for(j = 0;j < M;j++){if( temp < count[j] ){temp = count[j];point = j; // 获得离的最远的指针}}}else point = i;// 替换Block[point] = Data[i];count[point] = 0;// 保存要显示的数据for(j=0;j<M;j++){DataShow[j][i] = Block[j];DataShowEnable[i < M ?(j <= i ? j : i) : j][i] = true; // 设置显示数据}}// 输出信息printf("\nLRU => \n");DataOutput();}实验结果截图:程序运行:输入相应数据:选择相应算法:最佳置换算法:先进先出算法:最近最久未使用算法:。
操作系统实验三
1.分别从至少三个虚拟终端登录,以树状形式列出你的系统中当前运行的所有进程及其PID。
找出你当前运行进程的所有祖先进程,并说明其各自的作用。
分析Linux系统中的进程的家族关系。
tty1
tty2
tty3
所有进程的祖先进程为systemd,是linux下的一种init软件。
Linux 软件中init是一个由内核启动的用户级进程,内核自行启动(已经被载入内存,开始运行,并已初始化所有的设备驱动程序和数据结构等)之后,就通过启动一个用户级程序init的方式,完成引导进程。
所以init始终是第一个进程(其进程编号始终为1)。
init有许多很重要的任务,比如像启动getty(用于用户登录)、实现运行级别、以及处理孤立进程等。
操作系统实验报告实验名称:实现ls命令实验计算机科学与技术学院目录一、实验目的和要求 (2)二、实验内容 (2)三、实验步骤 (2)四、实验结果与分析 (3)1.输出当前目录下文件 (3)2.输出指定目录下文件 (3)五、程序源代码 (5)六、实验体会 (7)一、实验目的和要求在linux系统下用C语言编写一个程序实现linux 系统下ls 命令的功能。
二、实验内容问题:编写一个程序实现linux 系统下ls 命令的功能。
首先通过Linux系统的文件目录流打开函数DIR *opendir(const char *name); 来先打开文件目录,然后通过系统调用函数struct dirent *readdir(DIR *dirp); 读取文件目录下的文件信息。
其中文件结构体dirent的结构如下:struct dirent{ino_t d_ino; /* inode number */off_t d_off; /* offset to the next dirent */unsigned short d_reclen; /* length of this record */unsigned char d_type; /* type of file; not supported by all file system types */char d_name[256]; /* filename */};三、实验步骤根据实验要求,实现指令ls的基本功能,即实现列出当前目录下的文件名,还有就是实现列出指定目录下的所有文件的文件名信息。
在编写好代码之后编译代码然后输入指令测试实验结果是否符合要求。
四、实验结果与分析1、输入指令:./myls输入默认的指令,输出当前目录下的文件名称,并用不同颜色区分文件夹和文件的区别。
实验结果如下图图1所示:图1 输出当前目录下所有的文件名2、输入指令:./myls ./Documents给定一个制定的路径,输出所给定路径下所有文件的文件名。
结果如下图图2所示:图2 输出指定目录下的所有文件名五、程序源代码/**************************FileName:myls.c*Author:*Date:2014/1/5***************************/#include <stdio.h>#include <stdlib.h>#include <dirent.h>#include <errno.h>#include <string.h>#include <sys/ioctl.h>#include <unistd.h>#include <termios.h>#include <sys/stat.h>#define SPACE 4/*自定义的字符串结构体*/typedef struct{char *str;/*实际内容*/unsigned length;/*字符串长度*/}String;/*文件信息结构体*/typedef struct{unsigned length;/*集合中文件名的数量*/unsigned i,j;/*i是行数,j是列数*/String *filenames;unsigned maxlen;/*文件名集合中最大的文件名长度*/char **formats;/*格式化输出序列*/}FormatInfo;/*获取无符号整型数十进制数的长度*/unsigned unsigned_length(unsigned n){unsigned length = 0;do{++length;n /= 10;}while(n)return length;}/*预读根目录,将格式化输出的信息保存在info中*/void Preread(char *root, FormatInfo *info){DIR *dir;unsigned i,j,count = 0;struct dirent *ptr;String filename;unsigned *g = NULL;/*g是根据目录下的目录项名的长度进行分组的辅助变量*/ unsigned width = 0;unsigned group = 0;unsigned max = 0;unsigned row = 1;unsigned pos = 0;struct winsize t_size;ioctl(STDIN_FILENO, TIOCGWINSZ, &t_size);/*获取终端的行数和列数*/ if(info == NULL){printf("Error! \"info\" can not be NULL!\n");return;}dir = opendir(root);if(dir == NULL){perror("Fail to open dir.\n");exit(1);}while(readdir(dir)) ++count;/*统计文件和目录的个数*/rewinddir(dir);/*回卷读取目录的指针*/info->filenames = (String *)malloc(sizeof(String) * count);g = (unsigned *)malloc(sizeof(unsigned) * count);i = 0;/*获取文件或目录名和计算其长度*/while((ptr = readdir(dir)) != NULL){filename.str = ptr->d_name;/*文件或目录名*/filename.length = strlen(ptr->d_name);info->filenames[i++] = filename;}/*对目录项根据目录名或文件名用选择排序法从小到大进行排序*/ for(i=0;i<count;++i){for(j=i;j<count;++j){if(strcmp(info->filenames[i].str,info->filenames[j].str) > 0){filename = info->filenames[i];info->filenames[i] = info->filenames[j];info->filenames[j] = filename;}}}/*用试探的方法测试最后列表的组数*/group = count;/*先假定分为count个列表*/row = 1;/*每列的行数为1*/do{for(j=0,width=0;j<group;++j){for(i=0,max=0;i<row;++i){/*找出每一列中文件或目录名最长的那一个*/pos = j*row + i;if(pos >= count) break;if(info->filenames[pos].length > max){max = info->filenames[pos].length;g[j] = max;/*把每个列表的最大宽度存放到g数组里*/}}width += (max + SPACE);/*将各组最长的文件或目录名的长度相加,把列表之间的间隔也算上*/}/*假如其总宽度大于终端的宽度(列数),则把分组列表的数量减少,继续试探。
*/if(width >= t_size.ws_col){--group;row = (count%group)?(count/group+1):(count/group);}else{break;/*否则,估算列表的数量结束*/}}while(1);info->formats = (char **)malloc(sizeof(char *) * group);info->maxlen = 0;for(i=0;i<group;++i){if(g[i] > info->maxlen)info->maxlen = g[i];/*这里找出最大文件或目录名的长度*/g[i] += SPACE;/*把列表之间的间隔算上*/j = unsigned_length(g[i]) + 4;info->formats[i] = (char *)malloc(sizeof(char) * j);sprintf(info->formats[i],"%%-%us",g[i]);/*这里就是组织格式化输出字符串的关键部分*/info->formats[i][j] = '\0';}putchar('\n');info->length = count;info->i = row;/*列表行数*/info->j = group;/*列表数量*/free(g);closedir(dir);}void Myls(char *root){FormatInfo fi;int i,j,pos,len;char *filepath = NULL;struct stat buf;Preread(root,&fi);/*预读目录*/len = strlen(root);filepath = (char *)malloc(sizeof(char) * (strlen(root)+fi.maxlen+1));filepath[0] = '\0';strcat(filepath,root);if(filepath[len-1] != '/'){filepath[len++] = '/';}for(i=0,pos=0;i<fi.i;++i){for(j=0;j<fi.j;++j){pos = j*fi.i + i;if(pos < fi.length){filepath[len] = '\0';strcat(filepath, fi.filenames[pos].str);stat(filepath, &buf);if(S_ISDIR(buf.st_mode)){printf("\033[01;36m");//Set color_dark-green}else{printf("\033[0m");//Set default_color}printf(fi.formats[j],fi.filenames[pos]);}else if(i<fi.i){break;}else{putchar('\n');return;}}putchar('\n');}printf("\033[0m");//Restore default_colorfree(filepath);}int main(int argc, char *argv[]){if(argc < 1){printf("参数错误!/n"); exit(1);}else if(argc == 1){Myls(".");}else{Myls(argv[1]);}return 0;}六、实验体会这次实验明显感觉到比前两次实验要简单一些,因为这些内容都是C语言学过的一些基本运用,知识要套用Linux系统中文件目录相关的一些系统调用和文件结构而已,然后进行一些简单的文件读取,以及文件信息的整理排序输出就可以实现ls指令的基本功能——列出文件目录中文件的文件名等信息。