中原工学院操作系统实验报告_第1页
中原工学院操作系统实验报告_第2页
中原工学院操作系统实验报告_第3页
中原工学院操作系统实验报告_第4页
中原工学院操作系统实验报告_第5页
已阅读5页,还剩25页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

计算机操作系统实验报告专业:网络工程班级:162班学号:学生XX:指导教师:2019/06/061/30目录实验一进程控制3一、实验目的:3二、实验平台:4三、实验内容:4实验结果5单线程执行结果:7实验总结8实验二进程同步8一、实验目的:8二、实验平台:8三、实验内容:9执行结果12实验总结12实验三添加内核模块12一、实验目的:12二、实验平台:13三、实验内容:13readprocess.c代码:14Makefile代码:15processinfo文件源代码:17Makefile文件源代码:18实验总结20实验四统计操作系统缺页次数20实验目的20实验内容21实验过程211.修改内核源代码,添加统计变量212.配置编译新内核233.编译内核和模块244.安装新内核模块和新内核245.编写读取pfcount值的模块代码256.编译、构建内核模块267.加载模块到内核中26实验总结27实验五EXT4文件系统结构分析27一、实验目的:27二、实验平台:27三、实验内容:27实验总结312/30实验一进程控制一、实验目的:加深对进程概念的理解,明确进程和程序的区别;掌握Linux操作系统的进程创建和终止操作,体会父进程和子进程的关系及进程状态的变化;进一步认识并发执行的实质,编写并发程序。二、实验平台:虚拟机:VMWare9以上操作系统:Ubuntu12.04以上编辑器:Gedit|Vim编译器:Gcc三、实验内容:()编写一段程序,使用系统调用fork()创建两个子进程,当此程序运行时,在系统中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示“身份信息”“Parentprocess!PID=xxx1PPID=xxx2Childxprocess!PID=xxxPPID=xxx观察记录屏幕上的显示结果,并分析原因。说明:xxx1为进程号,用getpid()函数可获取进程号;xxx2为父进程号,用getppid()函数可获取父进程号;Childx中x为1和,用来区别两个子进程;wait()函数用来避免父进程在子进程终止之前终止。程序源码:#include<stdio.h>#include<unistd.h>#include<stdlib.h>#defineNUM2intmain(void){pid_tpid1,pid2;if((pid1=fork())<0){3/30printf("创建进程1失败");}else{if(pid1==0){//子进程1执行printf("Child1process:");printf("PID=%dPPID=%d\n",getpid(),getppid());sleep(2);}else{if((pid2=fork())<0){printf("创建进程2失败");}else{if(pid2==0){//子进程2执行printf("Child2process:");printf("PID=%dPPID=%d\n",getpid(),getppid());}else{//父进程执行wait();wait();printf("Parentprocess:");printf("PID=%dPPID=%d\n",getpid(),getppid());exit(0);}}}}}实验结果whtcmiss@whtcmiss-VirtualBox:~/Desktop$gcctest1.c-otestwhtcmiss@whtcmiss-VirtualBox:~/Desktop$./testChild2process:PID=2527PPID=2525Child1process:PID=2526PPID=2525Parentprocess:PID=2525PPID=21274/30whtcmiss@whtcmiss-VirtualBox:~/Desktop$./testChild2process:PID=2530PPID=2528Child1process:PID=2529PPID=2528Parentprocess:PID=2528PPID=2127whtcmiss@whtcmiss-VirtualBox:~/Desktop$./testChild2process:PID=2533PPID=2531Child1process:PID=2532PPID=2531Parentprocess:PID=2531PPID=2127实验结果分析:第一次程序运行结果,两个子进程的PPID都是2525,是由同一个进程创建。而父进程PID是2525,父进程PPID是2127,说明父进程也是一系统进程的子进程。第二次程序运行结果,父进程PID是2528,PPID是2127,说明父进程是由同一进程创建的,父进程也是以子进程的方式存在,且进程ID是逐渐递增的。()fork()和系列函数能同时运行多个程序,利用上述函数将下面单进程顺序执行的程序改造成可并发执行3个进程的程序multi_process.ctime命令获取程序的执行时间,比较单进程和多进程运行时间,并分析原因。//single.c#include<stdio.h>#defineNUM5intmain(void){voidprint_msg(char*m);print_msg("Good");print_msg("Morning");print_msg("201608030222\n");return0;}voidprint_msg(char*m){inti;for(i=0;i<NUM;i++){printf("%s",m);fflush(stdout);sleep(1);}}编译运行方法:#gccsingle.cosingle5/30#time./single单线程执行结果:多线程代码:#multi_process.c#include<stdio.h>#include<unistd.h>#include<stdlib.h>#defineNUM5intmain(void){pid_tpid[3];inti;for(i=1;i<=3;i++){pid[i-1]=fork();if(pid[i-1]==0||pid[i-1]==-1)break;}if(pid[0]==0){execl("print","print","Good",NULL);}else{if(pid[1]==0){execl("print","print","Hello",NULL);}else{if(pid[2]==0){execl("print","print","201608030222",NULL);}wait();wait();wait();exit(0);}}return0;}6/30实验分析:第二个实验结果,第二个程序的多线程因为是并发执行,而且是有三个线程,所以在时间上几乎是单线程的1/3,而且因为是并发的,所以打印结果是无序的。实验总结本次实验首先要明确进程和程序的区别,我通过在Linux操作系统的进程创建和终止操作,运行父进程和子进程,查看运行结果和进程状态的变化。实验过程中也了解了父进程与子进程的运行过程及其机制。实验二进程同步一、实验目的:掌握基本的同步算法,理解经典进程同步问题的本质;学习使用Linux的进程同步机制,掌握相关API的使用方法;能利用信号量机制,采用多种同步算法实现不会发生死锁的哲学家进餐程序。二、实验平台:虚拟机:VMWare9以上操作系统:Ubuntu12.04以上编辑器:Gedit|Vim编译器:Gcc7/30三、实验内:()以哲学家进餐模型为依据,Linux控制台环境下建5个进程,用semget函数创建一个信号量集(5个信号量,初为每一位哲学家饥饿,先拿起左手筷子,再拿起右手筷子;筷子是临界资源,为每一支筷子1个互斥信号量;想拿到筷子需要先对信号量P操作,使用完释放筷子对信号量V操作。伪代码描述:semaphorechopstick[5]={1,1,1,1,1};?第i位哲学家的活动可描述为:do{printf("%disthinking\n",i);printf("%dishungry\n",i);wait(chopstick[i]);//拿左筷子wait(chopstick[(i+1)%]);//拿右筷子printf("%diseating\n",i);signal(chopstick[i]);//放左筷子signal(chopstick[(i+1)%]);//放右筷子⋯}while[true];运行该组进程,观察进程是否能一直运行下,若停滞则发生了什么现象?并分析实验源码如下:#include<stdio.h>#include<stdlib.h>#include<string.h>#include<stdint.h>#include<stdbool.h>#include<errno.h>#include<unistd.h>#include<sys/types.h>#include<sys/stat.h>#include<sys/ipc.h>#include<sys/sem.h>#include<sys/wait.h>unionsemun{intval;structsemid_ds*buf;unsignedshort*array;8/30structseminfo*_buf;};#defineERR_EXIT(m)\do{\perror(m);\exit(EXIT_FAILURE);\}while(0)//获取互斥信号量voidwait_mutex(intmutex){structsembufsb={0,-1,0};semop(mutex,&sb,1);//对互斥信号量进行操作}//取得筷子voidwait_v(intsemid,intnum){structsembufsb={num,-1,0};semop(semid,&sb,1);}//释放筷子voidsignal_p(intsemid,intnum){structsembufsb={num,1,0};semop(semid,&sb,1);}//释放互斥变量mutexvoidsignal_mutex(intsemid0){structsembufsb={0,1,0};semop(semid0,&sb,1);}//ph函数voidph(intnum,intsemid,intsemid0){intleft=num;intright=(num+1)%5;for(;;){printf("%disthinking\n",num);sleep(1);printf("%dishungry\n",num);sleep(1);9/30//wait操作,控制哲学家最多4人能进餐wait_mutex(semid0);wait_v(semid,left);wait_v(semid,right);printf("%diseating\n",num);sleep(1);//signal操作signal_p(semid,right);//释放右筷子signal_p(semid,left);//释放左快子signal_mutex(semid0);//释放互斥信号量}}intmain(intargc,char*argv[]){intsemid,semid0;//创建两个信号量集semid0=semget(IPC_PRIVATE,1,IPC_CREAT|0666);semid=semget(IPC_PRIVATE,5,IPC_CREAT|0666);//unionsemunsu;su.val=1;inti;for(i=0;i<5;i++){//semctl()系统调用在一个信号量集或集合中的单个信号量)上执行各种控制操作semctl(semid,i,SETVAL,su);}//设定semid0信号量的初始值unionsemunsu0;su0.val=4;semctl(semid0,0,SETVAL,su0);//创建4个子进程intnum=0;pid_tpid;for(i=1;i<5;i++){pid=fork();if(pid<0){ERR_EXIT("fork");}if(pid==0){num=i;break;}}//第num个哲学家要做的事ph(num,semid,semid0);return0;}10/30执行结果实验总结哲学家进餐的问题是操作系统信号量同步的经典例题了。这次我通过解决哲学家进餐的哲学问题从而对进程同步有一个更好的理解,解决这个问题书中给出了三种解决方法。我在实验中也是用这三种方法去定义信号量解决死锁问题。通过信号量的获取与wait操作去控制进餐是通过互斥信号量的获取,若没有信号量便不能执行,而且只有四个哲学家能同时进餐也避免了死锁的出现。实验三添加内核模块一、实验目的:学习Linux模块的基本概念和原理,学习内核模块编程的基本技术,利用内核模块编程访问进程描述符,操作内核的基本数据结构,加深对进程的理解;理解proc文件系统的作用,学习proc文件的创建方法,掌握这种用户态和核心态通信的方法。11/30二、实验平台:虚拟机:VMWare9操作系统:Ubuntu12.04编辑器:Gedit|Vi三、实验内容:()阅读内核模块实例hello.c,掌握内核模块的主要构成;阅读Makefile文件,理解内核模块的编译方法及执行过程;掌握模块安装、卸载,以及查看模块信息的方法。将hello.o和Makefile文件放在一个文件夹workspacemake命令使其生成了hello.ko等文件,如图:使用命令载入模块,如图:使用命令显示载入系统的模块,如图:使用dmesg命令查看系统的内核模块信息如图:12/30使用sudormmodhello命令卸载该模块:()设计一个模块,功能是列出系统中所有内核进程的程序名、PID号和进程状态。主要步骤:阅读内核源代码,了解进程描述符task_struct中与本实验有关的成员项,以及访问进程队列的宏for_each_process;编写readprocess模块,获取进程信息;修改Makefile文件,编译、安装模块,查看输出信息;查看模块信息,卸载模块。源代码如下:代码:#include<linux/init.h>#include<linux/module.h>#include<linux/sched.h>#include<linux/list.h>MODULE_LICENSE("GPL");staticintmod_init_readprocess(void);staticvoidmod_exit_readprocess(void);module_init(mod_init_readprocess);module_exit(mod_exit_readprocess);13/30intmod_init_readprocess(void){printk(KERN_INFO"start\n");structtask_struct*p;printk("displaymoudleinfois:\n");for_each_process(p){printk("NAME:%s\t\tPID:%d\t\tSTATE:%ld\t\t\n",p->comm,p->pid,p->state);}return0;}voidmod_exit_readprocess(void){printk(KERN_INFO"end\n");}Makefile代码:ifneq($(KERNELRELEASE),)obj-m:=readprocess.oelseKDIR:=/lib/modules/$(shelluname-r)/buildPWD:=$(shellpwd)default:$(MAKE)-C$(KDIR)M=$(PWD)modulesclean:$(MAKE)-C$(KDIR)M=$(PWD)cleanEndif将process.c和Makefile文件放在同一个文件夹下使用make函数生成后缀为.ko文件:14/30使用命令载入模块,如图:使用lsmod命令显示载入系统的模块,如图:使用dmesg命令查看到系统的内核模块信息,如图:15/30使用sudorrmodhello命令卸载该模块,如图:(3)利用内核模块编程,在/proc目录下用自己的学号创建一个目录,如/proc/201300834101然后在学号目录下创建一个processinfo文件,如/proc/201300834101/processinfo,此文件为只读文件,用于显示所有内核进程的程序名、PID号和进程状态。主要步骤:修改(2)中readprocess模块,在模块初始化函数中创建目录及proc文件,并定义产生proc文件内容的函数(获取进程信息);在卸载模块函数中删除相应的proc文件及目录;修改Makefile文件,编译、安装模块;执行cat/proc/201300834101/processinfo命令,查看进程信息。文件源代码:#include<linux/init.h>#include<linux/module.h>#include<linux/sched.h>#include<linux/list.h>#include<linux/proc_fs.h>MODULE_LICENSE("GPL");staticintmod_init_readprocess(void);staticvoidmod_exit_readprocess(void);module_init(mod_init_readprocess);module_exit(mod_exit_readprocess);structproc_dir_entry*feeyu_dir,*processinfo_file;16/30intprocessinfo_read_procmem(char*page,char**start,off_toffset,intcount,int*eof,void*data);intmod_init_readprocess(void){printk(KERN_INFO"Let'sGo\n");feeyu_dir=proc_mkdir("201300824419",NULL);processinfo_file=create_proc_read_entry("processinfo",0,cg_dir,processinfo_read_procmem,NULL);return0;}voidmod_exit_readprocess(void){remove_proc_entry("processinfo",cg_dir);remove_proc_entry("201300824419",NULL);printk(KERN_INFO"ThankYou\n");}intprocessinfo_read_procmem(char*page,char**start,off_toffset,intcount,int*eof,void*data){intlen=0;structtask_struct*p;printk("所有内核进程信息:\n");for_each_process(p){len+=sprintf(page+len,"NAME:%sPID:%dSTATE:%ld\n",p->comm,p->pid,p->state);}returnlen;}Makefile文件源代码:ifneq($(KERNELRELEASE),)obj-m:=processinfo.oelseKDIR:=/lib/modules/$(shelluname-r)/buildPWD:=$(shellpwd)default:17/30$(MAKE)-C$(KDIR)M=$(PWD)modulesclean:$(MAKE)-C$(KDIR)M=$(PWD)cleanEndif加载模块:查看模块是否存在:查看模块信息:查看进程信息:18/30卸载模块后实验总结这次实验内容较多,重要是通过一些命令和代码对内核模块的进程进行操通过processinfo文件和makefile文件对内核中的进程进行读写等操作。实验很繁杂。但思路清晰后也能较完整的把整个实验做下来。通过这次实验,我对内核模块的操作及内核的一些进程上的操作有的一定的了解。实验四统计操作系统缺页次数实验目的学习虚拟内存的基本原理和Linux虚拟内存管理技术;深入理解、掌握Linux的按需调页过程;掌握内核模块的概念和操作方法,和向/proc文件系统中增加文件的方法;综合运用内存管理、系统调用、proc文件系统、内核编译的知识。19/30实验内容1.原理Linux的虚拟内存技术采用按需调页,当CPU请求一个不在内存中的页面时,会发生缺页,缺页被定义为一种异常(缺页异常)每种CPU结构都提供一个do_page_fault处理缺页中断。由于每发生一次缺页都要进入缺页中断服务函数do_page_fault一次,所以可以认为执行该函数的次数就是系统发生缺页的次数。因此可以定义一个全局变量pfcount作为计数变量,在执行do_page_fault时,该变量值加验通过动态加载模块的方法,利用/proc文件系统作为中介来获取该值。2.实验环境操作系统:Ubuntu12.04(内核版本为3.2.0-23-generic-pae)内核源码:linux-3.2.58实验过程1.下载一份内核源代码并解压Linux受GNU通用公共许可证(GPL其内核源代码是完全开放的。现在很多Linux的都提供内核代码的下载。推荐使用Linux的官方:://。在terminal下可以通过wget命令下载源代码:$cd/tmp$wget:///pub/linux/kernel/v3.x/linux-3.2.58.tar.xz切换到root身份,解压源代码到/usr/src目录下:#xzdlinux-3.2.58.tar.xz#tarxvflinux-3.2.58.tarC/usr/src2.修改内核源代码,添加统计变量、切换到预编译内核目录#cd/usr/src/linux-3.2.58、修改处理内存访问异常的代码//用vi编辑器打开fault.c,一般使用Intelx86体系结构,则修改arch/x86/目录下的文件#viarch/x86/mm/fault.c#cdarch/x86/mm#sudogeditfault.c20/30//在do_page_fault函数的上一行定义统计缺页次数的全局变量pfcountunsignedlongvolatilepfcount;//将pfcount加入到do_page_fault中,用以统计缺页次数pfcount++;、修改内存管理代码//用vi编辑器打开头文件mm.h21/30#viinclude/linux/mm.h//在mm.h中加入全局变量pfcount的声明,代码加在externintpage_cluster;语句之后externunsignedlongvolatilepfcount;、导出pfcount全局变量,让整个内核(包括模块)都可以访问。方法是:#cdkernel#sudogeditkallsyms.c//在文件最后加入一行代码EXPORT_SYMBOL(pfcount);3.配置编译新内核用编译Linux内核预备实验中的方法完成新内核的配置、编译、替换,重启后验证是否完成替换。在编译内核前,一般来说都需要对内核进行相应的配置。配置是精确控制新内核功能的机会。配置过程也控制哪些需编译到内核的二进制映像中(在启动时被载入),哪些是需要时才装入的内核模块(module首先进入内核源代码目录:#cd/usr/src/linux-3.2.58如果不是第一次编译的话,有必要将内核源代码树置于一种完整和一致的状态。因此,推荐执行命令makemrproper。它将清除目录下所有配置文件和先前生成核心时产生的.o文件:#makemrproper(如果是第一次可跳过此步)然后配置编译选项(此处使用原内核的配置文件,完整的配置命令看操作提示):#cp/boot/config-3.2.0-20-generic-pae.config该命令的作用是将原内核配置文件拷贝的当前目录下,并命名为.config。若需要进一步修改配置请参照操作提示。在编译前用#uname-r查看原来的版本22/304.编译内核和模块编译内核,就用:#make编译内核需要较长的时间,具体与机器的硬件条件及内核的配置等因素有关(采用VMWare虚拟机,需要约60分钟)。完成后产生的内核文件bzImage的位置在/usr/src/linux/arch/i386/boot目录下,当然这里假设用户的CPU是Intelx86型的,并且你将内核源代码放在/usr/src/linux目录下。如果选择了可加载模块,编译完内核后,要对选择的模块进行编译,可用:#makemodules5.安装新内核模块和新内核首先,用下面的命令将新内核模块安装到系统的标准模块目录中:#makemodules_install此处有改动选择了取消然后,用下面的命令将新内核安装到系统中:#makeinstall23/30通常,Linux在系统引导后从/boot目录下读取内核映像到内存中。因此如果想要使用自己编译的内核,就必须用makeinstall命令将启动文件(内核映像)安装到/boot目录下。6.编写读取pfcount值的模块代码系统重启后,执行如下操作:#mkdirsource//在当前用户目录下创建source文件夹,用于存放编写的用户程序#cdsource//切换到source目录#vipf.c//新建用于构建模块的代码/*pf.c*//*modulesprogram*/#include<linux/init.h>#include<linux/module.h>#include<linux/kernel.h>#include<linux/mm.h>#include<linux/proc_fs.h>#include<linux/string.h>#include<asm/uaccess.h>structproc_dir_entry*proc_pf;structproc_dir_entry*proc_pfcount;externunsignedlongpfcount;staticinlinestructproc_dir_entry*proc_pf_create(constchar*name,mode_tmode,read_proc_t*get_info){returncreate_proc_read_entry(name,mode,proc_pf,get_info,NULL);}intget_pfcount(char*buffer,char**start,off_toffset,intlength,int*peof,void*data){24/30intlen=0;len=sprintf(buffer,"%ld\n",pfcount);returnlen;}staticintpf_init(void){proc_pf=proc_mkdir("pf",0);proc_pf_create("pfcount",0,get_pfcount);return0;}staticvoidpf_exit(void){remove_proc_entry("pfcount",proc_pf);remove_proc_entry("pf",0);}module_init(pf_init);module_exit(pf_exit);MODULE_LICENSE("GPL");7编译、构建内核

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论