课程设计(综合实验)报告( 2014-- 2015年度第一学期)名称:操作系统综合实验题目:OS lab 综合实验院系:计算机系班级:计科1202学号:学生姓名:指导教师:赵文清王新颖设计周数:第八、九周成绩:日期:2014 年10月29日实验3 进程的创建一、实验目的练习使用EOS API函数CreateProcess创建一个进程,掌握创建进程的方法,理解进程和程序的区别。
调试跟踪CreateProcess函数的执行过程,了解进程的创建过程,理解进程是资源分配的单位。
二、实验内容1 准备实验2 练习使用控制台命令创建EOS应用程序的进程3 练习通过编程的方式让应用程序创建另一个应用程序的进程4 调试CreateProcess函数5 调试PsCreateProcess函数6 练习通过编程的方式创建应用程序的多个进程三、问题答案及参考代码1. 在源代码文件NewTwoProc.c提供的源代码基础上进行修改,要求使用hello.exe同时创建10个进程。
提示:可以使用PROCESS_INFORMATION类型定义一个有10个元素的数组,每一个元素对应一个进程。
使用一个循环创建10个子进程,然后再使用一个循环等待10个子进程结束,得到退出码后关闭句柄。
STARTUPINFO StartupInfo;PROCESS_INFORMATION ProcInfo[10];ULONG ulExitCode;INT nResult=0;。
int i,j;//#ifdef_DEBUG__asm("int $3\n nop");#endif printf("Create10p//rocessesand wait for the processes exit...\n\n");StartupInfo.StdInput = GetStdHandle(STD_INPUT_HANDLE);StartupInfo.StdOutput = GetStdHandle(STD_OUTPUT_HANDLE);StartupInfo.StdError = GetStdHandle(STD_ERROR_HANDLE);for(i =0; i < 10; i++)if(CreateProcess("A:\\Hello.exe",NULL,0,&StartupInfo,&ProcInfo[i]));else {for(j = 0; j < i; j++){WaitForSingleObject(ProcInfo[j].ProcessHandle, INFINITE);GetExitCodeProcess(ProcInfo[j].ProcessHandle, &ulExitCode);printf("\nThe process %d exit with %d.\n",j,ulExitCode);CloseHandle(ProcInfo[j].ProcessHandle);CloseHandle(ProcInfo[j].ThreadHandle); }printf("CreateProcess Failed,Error code:0x%X.\n",GetLastError());nResult = 1;return nResult; }for(i=0;i<10;i++){WaitForSingleObject(ProcInfo[i].ProcessHandle, INFINITE);GetExitCodeProcess(ProcInfo[i].ProcessHandle, &ulExitCode); }for(i=0i<10;i++){printf("\nThe process %d exit with %d.\n",i,ulExitCode);CloseHandle(ProcInfo[i].ProcessHandle);CloseHandle(ProcInfo[i].ThreadHandle); }return nResult;}3. 在PsCreateProcess函数中调用了PspCreateProcessEnvironment函数后又先后调用了PspLoadProcessImage和PspCreateThread函数,学习这些函数的主要功能。
能够交换这些函数被调用的顺序吗?思考其中的原因。
PspCreateProcessEnvironment 的主要功能是创建进程控制块,并且为进程创建了地址空间和分配了句柄表。
PspLoadProcessImage 是将进程的可执行映像加载到了进程的地址空间中。
PspCreateThread 创建了进程的主线程。
这三个函数被调用的顺序是不能够改变的。
就向上面描述的加载可执行映像之前必须已经为进程创建了地址空间,这样才能够确定可执行映像可以被加载到内存的什么位置。
在创建主线程之前必须已经加载了可执行映像,这样主线程才能够知道自己要从哪里开始执行,执行哪些指令。
因此不能交换他们的顺序。
实验4 线程的状态和转换一、实验目的调试线程在各种状态间的转换过程,熟悉线程的状态和转换。
通过为线程增加挂起状态,加深对线程状态的理解。
二、实验内容1 准备实验2 调试线程状态的转换过程(阻塞—就绪、运行—就绪、就绪—运行、运行—阻塞)3 为线程增加挂起状态三、问题答案及参考代码PsResumThread(IN HANDLE hThread){STATUS Status;BOOL IntState;PTHREAD Thread;Status=ObRefObjectByHandle(hThread,PspThreadType,(PVOID*)&Thread);if (EOS_SUCCESS(Status)){IntState = KeEnableInterrupts(FALSE);if (Zero == Thread->State) {ListRemoveEntry(&Thread->StateListEntry);PspReadyThread(Thread);PspThreadSchedule();Status = STATUS_SUCCESS;}else{Status = STATUS_NOT_SUPPORTED; }KeEnableInterrupts(IntState);//开中断ObDerefObject(Thread); }return Status;} resume命令执行的效果如图:1.思考一下,在本实验中,当loop线程处于运行状态时,EOS中还有哪些线程,它们分别处于什么状态。
可以使用控制台命令pt查看线程的状态。
2.当loop线程在控制台1中执行,并且在控制台2中执行suspend命令时,为什么控制台1中的loop线程处于就绪状态而不是运行状态?答:当在控制台2 中执行suspend命令时,实质上是优先级为24的控制台2线程抢占了处理器,也就是控制台2线程处于运行状态,所以此时loop线程处于就绪状态了。
4. 总结一下在图5-3中显示的转换过程,哪些需要使用线程控制块中的上下文(将线程控制块中的上下文恢复到处理器中,或者将处理器的状态复制到线程控制块的上下文中),哪些不需要使用,并说明原因。
答:一个进程在运行过程中或执行系统调用,或产生了一个中断事件,处理器都进行一次模式切换,操作系统接收控制权,有关系统例程完成必须的操作后,或恢复被中断进程或切换到新进程。
当系统调度新进程占有处理器时,新老进程随之发生上下文切换,因此,进程的运行被认为是在进程的上下文中执行,这时的控制权在操作系统手中,它在完成必要的操作后,可以恢复被中断的进程或切换到别的进程。
实验5 进程的同步一、实验目的使用EOS的信号量,编程解决生产者—消费者问题,理解进程同步的意义。
调试跟踪EOS信号量的工作过程,理解进程同步的原理。
修改EOS的信号量算法,使之支持等待超时唤醒功能(有限等待),加深理解进程同步的原理。
二、实验内容1 、准备实验2 、使用EOS的信号量解决生产者-消费者问题3 、调试EOS信号量的工作过程4、修改EOS的信号量算法if (Semaphore->Count>0){Semaphore->Count--;flag=STATUS_SUCCESS;}//如果信号量大于零,说明尚有资源,可以为线程分配elseflag=PspWait(&Semaphore->WaitListHead, Milliseconds);KeEnableInterrupts(IntState); // 原子操作完成,恢复中断。
return flag;}//否则,说明资源数量不够,不能再为线程分配资源,因此要使线程等待if (Semaphore->Count + ReleaseCount > Semaphore->MaximumCount) {Status = STATUS_SEMAPHORE_LIMIT_EXCEEDED;}Else{//记录当前的信号量的值//if(NULL!=PreviousCount){*PreviousCount=Semaphore->Count;}int mm=Semaphore->Count;//目前仅实现了标准记录型信号量,每执行一次信号量的释放操作只能使信号量的值增加1.//while ((!ListIsEmpty(&Semaphore->WaitListHead))&&(ReleaseCount)){ PspWakeThread(&Semaphore->WaitListHead, STATUS_SUCCESS);PspThreadSchedule();ReleaseCount--; }Semaphore->Count=mm+ReleaseCount;//可能有线程被唤醒,执行线程调度。
//Status=STATUS_SUCCESS:}三、问题答案及参考代码1.思考在ps/semaphore.c文件内的PsWaitForSemaphore和PsReleaseSemaphore函数中,为什么要使用原子操作?答:在执行释放信号量和等待信号量时,是不允许CPU响应外部中断的,否则,会产生不可预料的结果。
4.根据本实验3.3.2节中设置断点和调试的方法,自己设计一个类似的调试方案来验证消费者线程在消费24号产品时会被阻塞,直到生产者线程生产了24 号产品后,消费者线程才被唤醒并继续执行的过程。