合肥工业大学操作系统实验报告.docx
- 文档编号:25379373
- 上传时间:2023-06-07
- 格式:DOCX
- 页数:65
- 大小:781.29KB
合肥工业大学操作系统实验报告.docx
《合肥工业大学操作系统实验报告.docx》由会员分享,可在线阅读,更多相关《合肥工业大学操作系统实验报告.docx(65页珍藏版)》请在冰豆网上搜索。
合肥工业大学操作系统实验报告
操作系统实验报告
班级:
计算机科学与技术
姓名:
学号:
实验3进程的创建
一、实验目的
练习使用EOSAPI函数CreateProcess创建一个进程,掌握创建进程的方法,理解进程和程序的区别。
调试跟踪CreateProcess函数的执行过程,了解进程的创建过程,理解进程是资源分配的单位。
二、实验过程记录
1.
/*Hello.c*/
#include"EOSApp.h"
intmain(intargc,char*argv[])
{
inti;
for(i=1;i<=5;i++){
printf("Hello,world!
%d\n",i);
Sleep(1000);
}
printf("Bye-bye!
\n");
return0;
}
作用:
测试软盘镜像中的程序。
输出"Hello,world!
I”并循环输出五次,每次挂起1000ms,最后输出”Bye-bye!
”。
结果:
2.
/*NewProc.c*/
#include"EOSApp.h"
intmain(intargc,char*argv[])
{
STARTUPINFOStartupInfo;
PROCESS_INFORMATIONProcInfo;
ULONGulExitCode;//子进程退出码
INTnResult=0;//main函数返回值。
0表示成功,非0表示失败。
#ifdef_DEBUG
__asm("int$3\nnop");
#endif
printf("Createaprocessandwaitfortheprocessexit...\n\n");
//
//使子进程和父进程使用相同的标准句柄。
//
StartupInfo.StdInput=GetStdHandle(STD_INPUT_HANDLE);
StartupInfo.StdOutput=GetStdHandle(STD_OUTPUT_HANDLE);
StartupInfo.StdError=GetStdHandle(STD_ERROR_HANDLE);
//
//创建子进程。
//
if(CreateProcess("A:
\\Hello.exe",NULL,0,&StartupInfo,&ProcInfo)){
//
//创建子进程成功,等待子进程运行结束。
//
WaitForSingleObject(ProcInfo.ProcessHandle,INFINITE);
//
//得到并输出子进程的退出码。
//
GetExitCodeProcess(ProcInfo.ProcessHandle,&ulExitCode);
printf("\nTheprocessexitwith%d.\n",ulExitCode);
//
//关闭不再使用的句柄。
//
CloseHandle(ProcInfo.ProcessHandle);
CloseHandle(ProcInfo.ThreadHandle);
}else{
printf("CreateProcessFailed,Errorcode:
0x%X.\n",GetLastError());
nResult=1;
}
returnnResult;
}
作用:
软盘镜像引导成功后自动执行EOSAPP.exe,创建父进程,然后父进程首先开始执行并输出内容,父进程创建了子进程(Hello.exe)后,子进程开始执行并输出内容,待子进程结束后父进程再继续执行。
结果:
调试CreateProcess函数
1)按F5启动调试EOS应用程序,OSLab会首先弹出一个调试异常对话框。
2)选择“是”调试异常,调试会中断。
3)在main函数中调用CreateProcess函数的代码行(第57行)添加一个断点。
4)按F5继续调试,在断点处中断。
5)按F11调试进入CreateProcess函数。
此时已经开始进入EOS内核进行调试.
验证:
验证了了一个进程可以包含多个程序,该父进程包含了eosapp.exe和kernel.dll两个程序;内核(kernel.dll)处于高2G的虚拟地址空间中;应用程序(eosapp.exe)处于低2G的虚拟地址空间中.
数据展示:
CreateProcess函数的指令的虚拟地址都大于0x80000000;main函数的指令所在的虚拟地址都是小于0x80000000.
调试PsCreateProcess函数
调试PspCreateProcessEnvironment函数
1.在PsCreateProcess函数中找到调用PspCreateProcessEnvironment函数的代码行(create.c文件的第163行),并在此行添加一个断点。
2.按F5继续调试,到此断点处中断。
3.按F11调试进入PspCreateProcessEnvironment函数。
调试进程控制块的创建过程:
1.在调用ObCreateObject函数的代码行(create.c文件的第418行)添加一个断点。
2.按F5继续调试,到此断点处中断。
3.按F10执行此函数后中断。
4.此时为了查看进程控制块中的信息,将表达式*NewProcess添加到“监视”窗口中。
5.将鼠标移动到“监视”窗口中此表达式的“值”属性上,会弹出一个临时窗口,在临时窗口中会按照进程控制块的结构显示各个成员变量的值(可以参考PROCESS结构体的定义)。
由于只是新建了进程控制块,还没有初始化其中成员变量,所以值都为0。
接下来调试初始化进程控制块中各个成员变量的过程:
1.首先创建进程的地址空间,即4G虚拟地址空间。
在代码行(create.c文件的第437行)
NewProcess->Pas=MmCreateProcessAddressSpace();
添加一个断点。
2.按F5继续调试,到此断点处中断。
3.按F10执行此行代码后中断。
4.在“监视”窗口中查看进程控制块的成员变量Pas的值已经不再是0。
说明已经初始化了进程的4G虚拟地址空间。
5.使用F10一步步调试PspCreateProcessEnvironment函数中后面的代码,在调试的过程中根据执行的源代码,查看“监视”窗口中*NewProcess表达式的值,观察进程控制块中哪些成员变量是被哪些代码初始化的,哪些成员变量还没有被初始化。
6.当从PspCreateProcessEnvironment函数返回到PsCreateProcess函数后,停止按F10。
此时“监视”窗口中已经不能再显示表达式*NewProcess的值了,在PsCreateProcess函数中是使用ProcessObject指针指向进程控制块的,所以将表达式*ProcessObject添加到“监视”窗口中就可以继续观察新建进程控制块中的信息。
7.接下来继续使用F10一步步调试PsCreateProcess函数中的代码,同样要注意观察执行后的代码修改了进程控制块中的哪些成员变量。
当调试到PsCreateProcess函数的最后一行代码时,查看进程控制块中的信息,此时所有的成员变量都已经被初始化了(注意观察成员ImageName的值)。
8.按F5继续执行,EOS内核会为刚刚初始化完毕的进程控制块新建一个进程。
激活虚拟机窗口查看新建进程执行的结果。
9.在OSLab中选择“调试”菜单中的“停止调试”结束此次调试。
10.选择“调试”菜单中的“删除所有断点”。
验证:
在PsCreateProcess函数中首先调用了PspCreateProcessEnvironment函数来创建进程控制块.ObCreateObject函数会在由EOS内核管理的内存中创建了一个新的进程控制块(也就是分配了一块内存),并由NewProcess返回进程控制块的指针(也就是所分配内存的起始地址)
数据展示:
ObCreateObject函数创建新的进程控制块时*NewProcess,还没有初始化其中成员变量,所以值都为0。
初始化进程控制块中各个成员变量的过程中,进程控制块的成员变量Pas的值已经不再是0。
3.
/*NewTwoProc.c*/
#include"EOSApp.h"
intmain(intargc,char*argv[])
{
STARTUPINFOStartupInfo;
PROCESS_INFORMATIONProcInfoOne,ProcInfoTwo;
ULONGulExitCode;//子进程退出码
INTnResult=0;//main函数返回值。
0表示成功,非0表示失败。
#ifdef_DEBUG
__asm("int$3\nnop");
#endif
printf("Createtwoprocessesandwaitfortheprocessesexit...\n\n");
//
//使子进程和父进程使用相同的标准句柄。
//
StartupInfo.StdInput=GetStdHandle(STD_INPUT_HANDLE);
StartupInfo.StdOutput=GetStdHandle(STD_OUTPUT_HANDLE);
StartupInfo.StdError=GetStdHandle(STD_ERROR_HANDLE);
//
//为一个应用程序同时创建两个子进程。
//
if(CreateProcess("A:
\\Hello.exe",NULL,0,&StartupInfo,&ProcInfoOne)
&&CreateProcess("A:
\\Hello.exe",NULL,0,&StartupInfo,&ProcInfoTwo)){
//
//创建子进程成功,等待子进程运行结束。
//
WaitForSingleObject(ProcInfoOne.ProcessHandle,INFINITE);
WaitForSingleObject(ProcInfoTwo.ProcessHandle,INFINITE);
//
//得到并输出子进程的退出码。
//
GetExitCodeProcess(ProcInfoOne.ProcessHandle,&ulExitCode);
printf("\nTheprocessoneexitwith%d.\n",ulExitCode);
GetExitCodeProcess(ProcInfoTwo.ProcessHandle,&ulExitCode);
printf("\nTheprocesstwoexitwith%d.\n",ulExitCode);
//
//关闭不再使用的句柄。
//
CloseHandle(ProcInfoOne.ProcessHandle);
CloseHandle(ProcInfoOne.ThreadHandle);
CloseHandle(ProcInfoTwo.ProcessHandle);
CloseHandle(ProcInfoTwo.ThreadHandle);
}else{
printf("CreateProcessFailed,Errorcode:
0x%X.\n",GetLastError());
nResult=1;
}
returnnResult;
}
作用:
在eosapp.exe父进程下,为hello.exe创建两个子进程,分别等待两个子进程结束,得到退出码后关闭句柄。
结果:
交替分别显示两遍"Hello,world!
(1~5)”以及”Bye-bye!
”。
三、思考与练习
3.在PsCreateProcess函数中调用了PspCreateProcessEnvironment函数后又先后调用了PspLoadProcessImage和PspCreateThread函数,学习这些函数的主要功能。
能够交换这些函数被调用的顺序吗?
思考其中的原因。
答:
PspCreateProcessEnvironment的主要功能是创建进程控制块,并且为进程创建地址空间和分配句柄表。
PspLoadProcessImage是将进程的可执行映像加载到进程的地址空间中。
PspCreateThread创建了进程的主线程。
这三个函数被调用的顺序是不能够改变的。
加载可执行映像之前必须已经为进程分配了地址空间,这样才能够确定可执行映像可以被加载到内存的位置;在创建主线程之前必须已经加载过可执行映像,这样主线程才知道指令分工以及开始执行的位置。
因此不能交换他们的顺序。
四、备注说明
在机房完成。
实验5进程的同步
一、实验目的
使用EOS的信号量,编程解决生产者—消费者问题,理解进程同步的意义。
调试跟踪EOS信号量的工作过程,理解进程同步的原理。
修改EOS的信号量算法,使之支持等待超时唤醒功能(有限等待),加深理解进程同步的原理。
二、实验过程记录
1.
/*pc.c*/
#include"EOSApp.h"
//
//缓冲池。
//
#defineBUFFER_SIZE10
intBuffer[BUFFER_SIZE];
//
//产品数量。
//
#definePRODUCT_COUNT30
//
//用于生产者和消费者同步的对象句柄。
//
HANDLEMutexHandle;
HANDLEEmptySemaphoreHandle;
HANDLEFullSemaphoreHandle;
//
//生产者和消费者的线程函数
//
ULONGProducer(PVOIDParam);
ULONGConsumer(PVOIDParam);
//
//main函数参数的意义:
//argc-argv数组的长度,大小至少为1,argc-1为命令行参数的数量。
//argv-字符串指针数组,数组长度为命令行参数个数+1。
其中argv[0]固定指向当前
//进程所执行的可执行文件的路径字符串,argv[1]及其后面的指针指向各个命令行
//参数。
//例如通过命令行内容"a:
\hello.exe-a-b"启动进程后,hello.exe的main函
//数的参数argc的值为3,argv[0]指向字符串"a:
\hello.exe",argv[1]指向
//参数字符串"-a",argv[2]指向参数字符串"-b"。
//
intmain(intargc,char*argv[])
{
HANDLEProducerHandle;
HANDLEConsumerHandle;
#ifdef_DEBUG
__asm("int$3\nnop");
#endif
//
//创建用于互斥访问缓冲池的Mutex对象。
//
MutexHandle=CreateMutex(FALSE,NULL);
if(NULL==MutexHandle){
return1;
}
//
//创建Empty信号量,表示缓冲池中空缓冲区数量。
初始计数和最大计数都为BUFFER_SIZE。
//
EmptySemaphoreHandle=CreateSemaphore(BUFFER_SIZE,BUFFER_SIZE,NULL);
if(NULL==EmptySemaphoreHandle){
return2;
}
//
//创建Full信号量,表示缓冲池中满缓冲区数量。
初始计数为0,最大计数为BUFFER_SIZE。
//
FullSemaphoreHandle=CreateSemaphore(0,BUFFER_SIZE,NULL);
if(NULL==FullSemaphoreHandle){
return3;
}
//
//创建生产者线程。
//
ProducerHandle=CreateThread(0,//默认堆栈大小
Producer,//线程函数入口地址
NULL,//线程函数参数
0,//创建标志
NULL);//线程ID
if(NULL==ProducerHandle){
return4;
}
//
//创建消费者线程。
//
ConsumerHandle=CreateThread(0,
Consumer,
NULL,
0,
NULL);
if(NULL==ConsumerHandle){
return5;
}
//
//等待生产者线程和消费者线程结束。
//
WaitForSingleObject(ProducerHandle,INFINITE);
WaitForSingleObject(ConsumerHandle,INFINITE);
//
//关闭句柄
//
CloseHandle(MutexHandle);
CloseHandle(EmptySemaphoreHandle);
CloseHandle(FullSemaphoreHandle);
CloseHandle(ProducerHandle);
CloseHandle(ConsumerHandle);
return0;
}
//
//生产者线程函数。
//
ULONGProducer(PVOIDParam)
{
inti;
intInIndex=0;
for(i=0;i WaitForSingleObject(EmptySemaphoreHandle,INFINITE); WaitForSingleObject(MutexHandle,INFINITE); printf("Producea%d\n",i); Buffer[InIndex]=i; InIndex=(InIndex+1)%BUFFER_SIZE; ReleaseMutex(MutexHandle); ReleaseSemaphore(FullSemaphoreHandle,1,NULL); // //休息一会。 每500毫秒生产一个数。 // Sleep(500); } return0; } // //消费者线程函数。 // ULONGConsumer(PVOIDParam) { inti; intOutIndex=0; for(i=0;i WaitForSingleObject(FullSemaphoreHandle,INFINITE); WaitForSingleObject(MutexHandle,INFINITE); printf("\t\t\tConsumea%d\n",Buffer[OutIndex]); OutIndex=(OutIndex+1)%BUFFER_SIZE; ReleaseMutex(MutexHandle); ReleaseSemaphore(EmptySemaphoreHandle,1,NULL); // //休息一会儿。 让前10个数的消费速度比较慢,后面的较快。 // if(i<10){ Sleep(2000); }else{ Sleep(100); } } return0; } 作用: 演示生产者、消费者问题。 创建Mutex对象->创建Empty信号量对象->创建Full信号量对象->创建生产者线程->创建消费者线程->等待生产者线程和消费者线程结束->关闭句柄 结果: 调试EOS信号量的工作过程 创建信号量 1.按F5启动调试EOS应用项目。 OSLab会首先弹出一个调试异常对话框。 2.在调试异常对话框中选择“是”,调试会中断。 3.在main函数中创建Empty信号量的代码行(第77行) EmptySemaphoreHandle=CreateSemaphore(BUFFER_SIZE,BUFFER_SIZE,NULL); 添加一个断点。 4.按F5继续调试,到此断点处中断。 5.按F11调试进入CreateSemaphore函数。 可以看到此API函数只是调用了EOS内核中的PsCreateSemaphoreObject函数来创建信号量对象。 6.按F11调试进入semaphore.c文件中的PsCreateSemaphoreObject函数。 在此函数中,会在EOS内核管理的内存中创建一个信号量对象(分配一块内存),而初始化信号量对象中各个成员的操作是在PsInitializeSemaphore函数中完成的。 7.在semaphore.c文件的顶部查找到PsInitializeSemaphore函数的定义(第19行),在此函数的第一行(第39行)代码处添加一个断点。 8.按F5继续调试,到断点处中断。 观察PsInitializeSemaphore函数中用来初始化信号量结构体成员的值,应该和传入CreateSemaphore函数的参数值是一致的。 9.按F10单步调试PsInitializeSemaphore函数执行的过程,查看信号量结构体被初始化的过程。 打开“调用堆栈”窗口,查看函数的调用层次。 验证: CreateSemaphore函数只是调用了EOS内核中的PsCreateSe
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 合肥 工业大学 操作系统 实验 报告