河北工业大学2014操作系统实验报告 下载本文

2、 正在运行的进程 使用进程和操作系统的版本信息

运行结果:

当前PID信息:_4664

当前操作系统版本:5.1(我的操作系统为Windows XP)

系统提示信息:Task Manager should now now indicate this process is high priority.

程序向读者表明了如何获得当前的PID和所需的进程版本信息。为了运行这一程序,系统处理了所有的版本不兼容问题。

接着,程序演示了如何使用GetVersionEx() API函数来提取OSVERSIONINFOEX结构。这一数据块中包括了操作系统的版本信息。其中,“OS : 5.0”表示当前运行的操作系统是:Windows 2000。最后一段程序利用了操作系统的版本信息,以确认运行的是Windows 2000。代码接着将当前进程的优先级提高到比正常级别高。

单击Ctrl + Alt + Del键,进入“Windows任务管理器”,在“应用程序”选项卡中右键单击本任务,在快捷菜单中选择“转到进程”命令。

在“Windows任务管理器”的“进程”选项卡中,与本任务对应的进程映像名称是 (为什么?) : VCSPAWN.EXE

右键单击该进程名,在快捷菜单中选择“设置优先级”命令,可以调整该进程的优先级,如设置为“高”后重新运行程序,屏幕显示有变化吗? 没有。

3、 终止进程

指令其子进程来“杀掉”自己的父进程

程序说明了一个进程从“生”到“死”的整个一生。第一次执行时,它创建一个子进程,其行为如同“父亲”。在创建子进程之前,先创建一个互斥的内核对象,其行为对于子进程来说,如同一个“自杀弹”。当创建子进程时,就打开了互斥体并在其他线程中进行别的处理工作,同时等待着父进程使用ReleaseMutex() API发出“死亡”信号。然后用Sleep() API调用来模拟父进程处理其他工作,等完成时,指令子进程终止。

当调用ExitProcess() 时要小心,进程中的所有线程都被立刻通知停止。在设计应用程序时,必须让主线程在正常的C++ 运行期关闭 (这是由编译器提供的缺省行为) 之后来调用这一函数。当它转向受信状态时,通常可创建一个每个活动线程都可等待和停止的终止事件。

在正常的终止操作中,进程的每个工作线程都要终止,由主线程调用ExitProcess()。接着,管理层对进程增加的所有对象释放引用,并将用 GetExitCodeProcess() 建立的退出代码从STILL_ACTIVE改变为在ExitProcess() 调用中返回的值。最后,主线程对象也如同进程对象一样转变为受信状态。

等到所有打开的句柄都关闭之后,管理层的对象管理器才销毁进程对象本身。还没有一种函数可取得终止后的进程对象为其参数,从而使其“复活”。当进程对象引用一个终止了的对象时,有好几个API函数仍然是有用的。进程可使用退出代码将终止方式通知给调用GetExitCodeProcess() 的其他进程。同时,GetProcessTimes() API函数可向主调者显示进程的终止时间。

运行结果:

1) _Creating the child process._

Child waiting for suicide instructions.

表示:_父进程正在创建子进程。子进程等待父进程杀死子进程。_ 2) _Telling the child process to quit.__ 表示:_父进程杀死子进程。_ 四、实验总结

请总结一下本次实验的收获、教训和感受,结合课本内容谈一下你对进程的理解。

本次实验让我明白进程是程序的一次执行过程,是系统进行处理机调度和资源分配的基本单位。(未引入线

5

程之前)。进程是操作系统结构的基础;是一个正在执行的程序;计算机中正在运行的程序实例;可以分配给处理器并由处理器执行的一个实体;由单一顺序的执行显示,一个当前状态和一组相关的系统资源所描述的活动单元,对父进程和子进程的关系有了进一步的了解。

实验二 并发与调度

1、 实验目的

在本实验中,通过对事件和互斥体对象的了解,来加深对Windows 2000线程同步的理解。通过分析实验程序,了解管理事件对象的API。了解在进程中如何使用事件对象,在进程中如何使用互斥体对象,线程如何通过文件映射对象发送数据。 二、实验内容和步骤 第一部分:互斥体对象

本程序中显示的类CCountUpDown使用了一个互斥体来保证对两个线程间单一数值的访问。每个线程都企图获得控制权来改变该数值,然后将该数值写入输出流中。创建者实际上创建的是互斥体对象,计数方法执行等待并释放,为的是共同使用互斥体所需的资源 (因而也就是共享资源) 。

1、利用互斥体保护共享资源

分析程序的运行结果,可以看到线程 (加和减线程) 的交替执行 (因为Sleep() API允许Windows切换线程) 。在每次运行之后,数值应该返回初始值 (0) ,因为在每次运行之后写入线程在等待队列中变成最后一个,内核保证它在其他线程工作时不会再运行。

1) 请描述运行结果 (如果运行不成功,则可能的原因是什么?) :

两个线程交替运行,不断改变value的值。两个线程互斥访问Value的值。

2) 根据运行输出结果,对照分析程序,可以看出程序运行的流程吗?请简单描述:

线程1(5296)先运行,将value值增1,变为1。然后,线程2(6016)运行,将value值减1,变为0. 第二部分:线程通过文件对象发送数据

Windows 2000提供的线程间通讯类内核对象允许同一进程或跨进程的线程之间互相发送信息,包括文件、文件映射、邮件位和命名管道等,其中最常用的是文件和文件映射。这类对象允许一个线程很容易地向同一进程或其他进程中的另一线程发送信息。 1、演示线程通过文件对象发送数据

运行结果 (如果运行不成功,则可能的原因是什么?) :

6

阅读和分析程序,请回答问题:

1) 程序中启动了多少个单独的读写线程? 100

2) 使用了哪个系统API函数来创建线程例程?

CreateThread()

3) 文件的读和写操作分别使用了哪个API函数?

ReadFile() WriteFile()

每次运行进程时,都可看到程序中的每个线程从前面的线程中读取数据并将数据增加,文件中的数值连续增加。这个示例是很简单的通讯机制。可将这一示例用作编写自己的文件读/写代码的模板。

请注意程序中写入之前文件指针的重置。重置文件指针是必要的,因为该指针在读取结束时将处于前四个字节之后,同一指针还要用于向文件写入数据。如果函数向该处写入新数值,则下次进程运行时,只能读到原来的数值。那么:

4) 在程序中,重置文件指针使用了哪一个函数?

SetFilePointer()

5)从输出结果,对照分析程序,可以看出程序运行的流程吗?请简单描述:

首先创建一个线程,读nValue的值,然后nValue值加一后,将nValue值重新写入文件。重复上述过程100次。

2、演示使用映射文件的内存交换数据的线程 阅读和分析程序,请回答:

1) 程序中用来创建一个文件映射对象的系统API函数是哪个? CreateFileMapping();

2) 在文件映射上创建和关闭文件视图分别使用了哪一个系统函数? a.MapViewOfFile() b.UnmapViewOfFile()

3) 运行时,程序首先通过 (MakeSharedFile(); ) 函数创建一个小型的文件映射对象 ( hMapping) ,接着,使用系统API函数 ( CreateMutex();) 再创建一个保护其应用的互斥体 ( g_hMutexMapping ) 。然后,应用程序创建100个线程,每个都允许进行同样的进程,即:通过互斥体获得访问权,这个操作是由语句:_WaitForSingleObject(g_hMutexMapping, INFINITE);实现的。再通过函数 ( MapViewOfFile(); ) 操作将视图映射到文件,将高32位看作有符号整数,将该数值增加 (即命令:++(*pnData); ) ,再将新数值显示在控制台上。每个线程清除文件的视图并在退出之前释放互斥体的语句是ReleaseMutex(g_hMutexMapping);。当线程完成时,应用程序关闭并退出。

4) 将程序中的语句 :: Sleep(500) ; 删除 (例如在语句前面加上“//”) 后,重新编译运行,结果有变化吗?为什么?

有变化。100个线程一闪而过,不能看清结果。 因为Sleep(500)是为了放慢速度,方便观察。 四、实验总结

请总结一下本次实验的收获、教训和感受,结合课本内容谈一下你对进程间控制的理解。

本次实验让我明白了操作系统中的事件和互斥体对象,以及线程同步的概念。学习了进程中如何使用事

件对象,在进程中如何使用互斥体对象,线程如何通过文件映射对象发送数据。当多个进程并发执行时,若我们

7

不指定进程之间并发的顺序,则他们可以任意并发,当这些进程没有访问互斥元素时,运行结果不会出现错误,但是当多个进程访问同一个互斥体时,就会出现错误,这时我们必须通过某种手段来同步进程间并发的顺序,这便是进程间的同步问题。

还有,并发执行的进程或线程间,有时为了需要,会相互之间进行数据的交换,即进程间通信,Windows

中,可以通过文件对象在线程间发送数据。还可以使用映射文件的内存交换数据。

实验三 生产者-消费者算法模拟实验

一、实验目的

1、掌握基本的互斥与同步算法,进一步理解“生产者-消费者”模型。

2、通过对“生产者-消费者”问题编程实现,了解线程创建、同步信号量、互斥信号量、临界区的创建和使用,初步了解并发程序设计方法。

3、进一步理解P、V原语和信号量在线程互斥和同步机制中的运用。 二、实验内容和步骤

1、在本次实验开始,以“生产者-消费者”模型为依据,提供了一个多线程“生产者-消费者”实例,有部分源程序代码,要求读者分析已编制的一个“生产者-消费者”实例,并将其缺失的程序代码补充完整,然后调试这段程序,得出最终的结果,并分析结果,得出相应的结论。

尝试改变一些参数,例如:改变缓冲区数、增加(减少)线程数、改变延迟数、增加(减少)生产者进程、增加(减少)消费者进程、改变消费者进程的请求序列等内容,考察这些改变对于运行结果的影响。 3、参考部分源程序代码:

1、empty_semaphore=CreateSemaphore(NULL,n_Buffer_or_Critical,n_Buffer_or_Critical, \2、h_mutex =CreateMutex(NULL,FALSE,\3、h_Semaphore[j+1]=CreateSemaphore(NULL,0,n_Thread,lp.c_str()); 4、h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(Produce), &(Thread_Info[i]),0,NULL);

5、h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(Consume), &(Thread_Info[i]),0,NULL); 6、ReleaseMutex(h_mutex);

7、ReleaseSemaphore(h_Semaphore[m_serial],n_Thread,NULL); 8、EnterCritialSection(&PC_Critical[BufferPos]); 9、ReleaseSemaphore(empty_semaphore,1,NULL); 10、LeaveCriticalSection(&PC_Critical[BufferPos]);

4、请补全上述程序,写出程序的运行结果。程序运行结果如下图所示。

8