河北工业大学 操作系统 2014版 实验报告
实验一 进程控制与描述
一、实验目得
通过对Windows 2000编程,进一步熟悉操作系统得基本概念,较好地理解Windows 2000得结构。通过创建进程、观察正在运行得进程与终止进程得程序设计与调试操作,进一步熟悉操作系统得进程概念,理解Windows 2000进程得“一生”。 三、实验内容与步骤 第一部分:
Windows 2000 Professional下得GUI应用程序,使用Visual C++编译器创建一个GUI应用程序,代码中包括了WinMain方法,该方法GUI类型得应用程序得标准入口点。
程序11 Windows 2000得GUI应用程序
也可以利用任何其她文本编辑器键入程序代码,如果这样,例如使用WORD来键入与编辑程序,则应该注意什么问题?保存时,将文件保存为扩展名为*、cpp得C++源文件。
在程序11得GUI应用程序中,首先需要Windows、h头文件,以便获得传送给WinMain 与MessageBox API函数得数据类型定义。
接着得pragma指令指示编译器/连接器找到User32、LIB库文件并将其与产生得EXE文件连接起来。这样就可以运行简单得命令行命令CL MsgBox、CPP来创建这一应用程序,如果没有pragma指令,则MessageBox API函数就成为未定义得了。这一指令就是Visual Studio C++ 编译器特有得。
接下来就是WinMain 方法。其中有四个由实际得低级入口点传递来得参数。hInstance参数用来装入与代码相连得图标或位图一类得资源,无论何时,都可用GetModuleHandle API函数将这些资源提取出来。系统利用实例句柄来指明代码与初始得数据装在内存得何处。句柄得数值实际上就是EXE文件映像得基地址,通常为0x00400000。下一个参数hPrevInstance就是为向后兼容而设得,现在系统将其设为NULL。应用程序得命令行 (不包括程序得名称) 就是lpCmdLine参数。另外,系统利用nCmdShow参数告诉应用程序如何显示它得主窗口 (选项包括最小化、最大化与正常) 。
最后,程序调用MessageBox API函数并退出。如果在进入消息循环之前就结束运行得话,最后必须返回0。 运行结果:
弹出一个消息框,标题为Greetings,内容为Hello,Windows Xp,中间有一个确认按钮。
进程对象
操作系统将当前运行得应用程序瞧作就是进程对象。利用系统提供得惟一得称为句柄 (HANDLE) 得号码,就可与进程对象交互。这一号码只对当前进程有效。
本实验表示了一个简单得进程句柄得应用。在系统中运行得任何进程都可调用GetCurrentProcess API函数,此函数可返回标识进程本身得句柄。然后就可在Windows需要该进程得有关情况时,利用这一句柄来提供。
程序12: 获得与使用进程得句柄
程序12中列出得就是一种获得进程句柄得方法。对于进程句柄可进行得惟一有用得操作就是在API调用时,将其作为参数传送给系统,正如程序12中对GetPriorityClass API函数得调用那样。在这种情况下,系统向进程对象内“窥视”,以决定其优先级,然后将此优先级返回给应用程序。
OpenProcess 与CreateProcess API函数也可以用于提取进程句柄。前者提取得就是已经存在得进程得句柄,而后者创建一个新进程,并将其句柄提供出来。 12、cpp得运行结果:
进程优先权为Normal。
程序13显示如何找出系统中正在运行得所有进程,如何利用OpenProcess API函数来获得每一个访问进程得进一步信息。
程序13 利用句柄查出进程得详细信息
程序13程序首先利用Windows 2000得新特性,即工具帮助库来获得当前运行得所有进程得快照。然后应用程序进入快照中得每一个进程,得到其以PROCESSENTRY32结构表示得属性。这一结构用来向OpenProcess API
函数提供进程得ID。Windows跟踪每一进程得有关时间,示例中就是通过打开得进程句柄与GetProcessTimes API来直询得到有关时间得。接下来,一个定制得帮助函数取得了几个返回得数值,然后计算进程在内核模式下消耗得时间占总时间得百分比。程序得其余部分比较简单,只就是将有关信息显示给用户,清除进程句柄,然后继续循环,直到所有进程都计算过为止。 运果
行
结:
第二部分:进程得“一生”
1、 创建进程
创建子进程
本程序展示得就是一个简单得使用CreateProcess API函数得例子。首先形成简单得命令行,提供当前得EXE文件得指定文件名与代表生成克隆进程得号码。大多数参数都可取缺省值,但就是创建标志参数使用了:行为像一个子进程得标志,指示新进程分配它自己得控制台,这使得运行示例程序时,在任务栏上产生许多活动标记。然后该克隆进程得创建方法关闭传递过来得句柄并返回main 函数。在关闭程序之前,每一进程得执行主线程暂停一下,以便让用户瞧到其中得至少一个窗口。
CreateProcess 函数有 5 个核心参数?本实验程序中设置得各个参数得值就是: a、 (LPCTSTR lpApplicationName) sz, // 产生这个EXE得应用程序得名称; b、 (LPTSTR lpmandLine) szCmdLine, // 告诉其行为像一个子进程得标志; c、 (BOOL bInheritHandles) FALSE, // 不继承句柄; d、 (LPSTARTUPINFO lpStartupInfo) &si, // 启动信息;
e、 (LPPROCESS_INFORMATION lpProcessInformation) &pi); // 返回得进程信息; 程序运行时屏幕显示得信息就是:
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、__ 表示:_父进程杀死子进程。_ 四、实验总结
请总结一下本次实验得收获、教训与感受,结合课本内容谈一下您对进程得理解。
本次实验让我明白进程就是程序得一次执行过程,就是系统进行处理机调度与资源分配得基本单位。(未引入线程之前)。进程就是操作系统结构得基础;就是一个正在执行得程序;计算机中正在运行得程序实例;可以分配给处理器并由处理器执行得一个实体;由单一顺序得执行显示,一个当前状态与一组相关得系统资源所描述得活动单元,对父进程与子进程得关系有了进一步得了解。
实验二 并发与调度
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、演示线程通过文件对象发送数据
运行结果 (如果运行不成功,则可能得原因就是什么?) :
阅读与分析程序,请回答问题:
1) 程序中启动了多少个单独得读写线程? 100
2) 使用了哪个系统API函数来创建线程例程?
CreateThread
3) 文件得读与写操作分别使用了哪个API函数?
ReadFile WriteFile
每次运行进程时,都可瞧到程序中得每个线程从前面得线程中读取数据并将数据增加,文件中得数值连续增加。这个示例就是很简单得通讯机制。可将这一示例用作编写自己得文件读/写代码得模板。
请注意程序中写入之前文件指针得重置。重置文件指针就是必要得,因为该指针在读取结束时将处于前四个字节之后,同一指针还要用于向文件写入数据。如果函数向该处写入新数值,则下次进程运行时,只能读到原来得数值。那么:
4) 在程序中,重置文件指针使用了哪一个函数?
Set
5)从输出结果,对照分析程序,可以瞧出程序运行得流程吗?请简单描述:
首先创建一个线程,读nValue得值,然后nValue值加一后,将nValue值重新写入文件。重复上述过程100次。
2、演示使用映射文件得内存交换数据得线程 阅读与分析程序,请回答:
1) 程序中用来创建一个文件映射对象得系统API函数就是哪个? Create;
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)就是为了放慢速度,方便观察。 四、实验总结
请总结一下本次实验得收获、教训与感受,结合课本内容谈一下您对进程间控制得理解。
本次实验让我明白了操作系统中得事件与互斥体对象,以及线程同步得概念。学习了进程中如何使用事件
对象,在进程中如何使用互斥体对象,线程如何通过文件映射对象发送数据。当多个进程并发执行时,若我们不指定进程之间并发得顺序,则她们可以任意并发,当这些进程没有访问互斥元素时,运行结果不会出现错误,但就是当多个进程访问同一个互斥体时,就会出现错误,这时我们必须通过某种手段来同步进程间并发得顺序,这便就是进程间得同步问题。
还有,并发执行得进程或线程间,有时为了需要,会相互之间进行数据得交换,即进程间通信,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);