操作系统实验报告.docx
《操作系统实验报告.docx》由会员分享,可在线阅读,更多相关《操作系统实验报告.docx(83页珍藏版)》请在冰豆网上搜索。
操作系统实验报告
操作系统
实验报告
实验一进程控制与描述
一、实验目的
通过对Windows2000编程,进一步熟悉操作系统的基本概念,较好地理解Windows2000的结构。
通过创建进程、观察正在运行的进程和终止进程的程序设计和调试操作,进一步熟悉操作系统的进程概念,理解Windows2000进程的“一生”。
二、实验环境
硬件环境:
计算机一台,局域网环境;
软件环境:
Windows2000Professional,VisualC++6.0专业版或企业版。
三、实验内容和步骤
第一部分:
Windows2000Professional下的GUI应用程序,使用VisualC++编译器创建一个GUI应用程序,代码中包括了WinMain()方法,该方法GUI类型的应用程序的标准入口点。
在“开始”菜单中单击“程序”-“附件”-“记事本”命令,将程序键入记事本中,并把代码保存为1-1.cpp。
程序1-1Windows2000的GUI应用程序
//msgbox项目
#include//标准的include
//告诉连接器与包括MessageBoxAPI函数的user32库进行连接
#pragmacomment(lib,“user32.lib”)
//这是一个可以弹出信息框然后退出的筒单的应用程序
intAPIENTRYWinMain(HINSTANCE/*hInstance*/,
HINSTANCE/*hPrevInstance*/,
LPSTR/*lpCmdLine*/,
int/*nCmdShow*/)
{
:
:
MessageBox(
NULL,//没有父窗口
“Hello,Windows2000”,//消息框中的文本
“Greetings”,//消息框标题
MB_OK);//其中只有一个OK按钮
//返回0以便通知系统不进入消息循环
return(0);
}
也可以利用任何其他文本编辑器键入程序代码,如果这样,例如使用WORD来键入和编辑程序,则应该注意什么问题?
答:
应该注意全角和半角字。
在“命令提示符”窗口运行CL.EXE,产生1-1.EXE文件:
C:
\>CL1-1.cpp
在程序1-1的GUI应用程序中,首先需要Windows.h头文件,以便获得传送给WinMain()和MessageBox()API函数的数据类型定义。
接着的pragma指令指示编译器/连接器找到User32.LIB库文件并将其与产生的EXE文件连接起来。
这样就可以运行简单的命令行命令CLMsgBox.CPP来创建这一应用程序,如果没有pragma指令,则MessageBox()API函数就成为未定义的了。
这一指令是VisualStudioC++编译器特有的。
接下来是WinMain()方法。
其中有四个由实际的低级入口点传递来的参数。
hInstance参数用来装入与代码相连的图标或位图一类的资源,无论何时,都可用GetModuleHandle()API函数将这些资源提取出来。
系统利用实例句柄来指明代码和初始的数据装在内存的何处。
句柄的数值实际上是EXE文件映像的基地址,通常为0x00400000。
下一个参数hPrevInstance是为向后兼容而设的,现在系统将其设为NULL。
应用程序的命令行(不包括程序的名称)是lpCmdLine参数。
另外,系统利用nCmdShow参数告诉应用程序如何显示它的主窗口(选项包括最小化、最大化和正常)。
最后,程序调用MessageBox()API函数并退出。
如果在进入消息循环之前就结束运行的话,最后必须返回0。
运行结果(试将其中的信息与程序3-1程序的运行结果进行比较):
进程对象
操作系统将当前运行的应用程序看作是进程对象。
利用系统提供的惟一的称为句柄(HANDLE)的号码,就可与进程对象交互。
这一号码只对当前进程有效。
本实验表示了一个简单的进程句柄的应用。
在系统中运行的任何进程都可调用GetCurrentProcess()API函数,此函数可返回标识进程本身的句柄。
然后就可在Windows需要该进程的有关情况时,利用这一句柄来提供。
程序1-2:
获得和使用进程的句柄
//prochandle项目
#include
#include
//确定自己的优先权的简单应用程序
voidmain()
{
//从当前进程中提取句柄
HANDLEhProcessThis=:
:
GetCurrentProcess();
//请求内核提供该进程所属的优先权类
DWORDdwPriority=:
:
GetPriorityClass(hProcessThis);
//发出消息,为用户描述该类
std:
:
cout<<“Currentprocesspriority:
”;
switch(dwPriority)
{
caseHIGH_PRIORITY_CLASS:
std:
:
cout<<“High”;
break;
caseNORMAL_PRIORITY_CLASS:
std :
:
cout<< “Normal”;
break;
caseIDLE_PRIORITY_CLASS:
std:
:
cout<<“Idle”;
break;
caseREALTIME_PRIORITY_CLASS:
std:
:
cout<<“Realtime”;
break;
default:
std:
:
cout<<“”;
break;
}
std:
:
cout<:
endl;
}
程序1-2中列出的是一种获得进程句柄的方法。
对于进程句柄可进行的惟一有用的操作是在API调用时,将其作为参数传送给系统,正如程序1-2中对GetPriorityClass()API函数的调用那样。
在这种情况下,系统向进程对象内“窥视”,以决定其优先级,然后将此优先级返回给应用程序。
OpenProcess()和CreateProcess()API函数也可以用于提取进程句柄。
前者提取的是已经存在的进程的句柄,而后者创建一个新进程,并将其句柄提供出来。
在“命令提示符”窗口运行CL.EXE,产生1-2.EXE文件:
C:
\>CL1-2.cpp
运行结果:
将程序1-3.cpp程序键入记事本中,并把代码保存为1-3.cpp。
程序1-3显示如何找出系统中正在运行的所有进程,如何利用OpenProcess()API函数来获得每一个访问进程的进一步信息。
程序1-3利用句柄查出进程的详细信息
//proclist项目
#include
#include
#include
//当在用户模式机内核模式下都提供所耗时间时,在内核模式下进行所耗时间的64位计算的帮助方法
DWORDGetKernelModePercentage(constFILETIME&ftKernel,
constFILETIME&ftUser)
{
//将FILETIME结构转化为64位整数
ULONGLONGqwKernel=
(((ULONGLONG)ftKernel.dwHighDateTime)<<32)+
ftKernel.dwLowDateTime;
ULONGLONGqwUser=
(((ULONGLONG)ftUser.dwHighDateTime)<<32)+
ftUser.dwLowDateTime;
//将消耗时间相加,然后计算消耗在内核模式下的时间百分比
ULONGLONGqwTotal=qwKernel+qwUser;
DWORDdwPct=
(DWORD)(((ULONGLONG)100*qwKernel)/qwTotal);
return(dwPct);
}
//以下是将当前运行进程名和消耗在内核模式下的时间百分数都显示出来的应用程序
voidmain()
{
//对当前系统中运行的进程拍取“快照”
HANDLEhSnapshot=:
:
CreateToolhelp32Snapshot(
TH32CS_SNAPPROCESS,//提取当前进程
0);//如果是当前进程,就将其忽略
//初始化进程入口
PROCESSENTRY32pe;
:
:
ZeroMemory(&pe,sizeof(pe));
pe.dwSize=sizeof(pe);
//按所有进程循环
BOOLbMore=:
:
Process32First(hSnapshot,&pe);
while(bMore)
{
//打开用于读取的进程
HANDLEhProcess=:
:
OpenProcess(
PROCESS_QUERY_INFORMATION,//指明要得到信息
FALSE,//不必继承这一句柄
pe.th32ProcessID);//要打开的进程
if(hProcess!
=NULL)
{
//找出进程的时间
FILETIMEftCreation,ftExit,ftKernelMode,ftUserMode;
:
:
GetProcessTimes(
hProcess,//所感兴趣的进程
&ftCreation,//进程的启动时间(绝对的)
&ftExit,//结束时间(如果有的话)
&ftKernelMode,//在内核模式下消耗的时间
&ftUserMode);//在用户模式下消耗的时间
//计算内核模式消耗的时间百分比
DWORDdwPctKernel=:
:
GetKernelModePercentage(
ftKernelMode,//在内核模式上消耗的时间
ftUserMode);//在用户模式下消耗的时间
//向用户显示进程的某些信息
std:
:
cout<<“ProcessID:
”<<<“,EXEfile:
”<<<“,%inkernelmode:
”<<:
endl;
//消除句柄
:
:
CloseHandle(hProcess);
}
//转向下一个进程
bMore=:
:
Process32Next(hSnapshot,&pe);
}
}
程序1-3程序首先利用Windows2000的新特性,即工具帮助库来获得当前运行的所有进程的快照。
然后应用程序进入快照中的每一个进程,得到其以PROCESSENTRY32结构表示的属性。
这一结构用来向OpenProcess()API函数提供进程的ID。
Windows跟踪每一进程的有关时间,示例中是通过打开的进程句柄和GetProcessTimes()API来直询得到有关时间的。
接下来,一个定制的帮助函数取得了几个返回的数值,然后计算进程在内核模式下消耗的时间占总时间的百分比。
程序的其余部分比较简单,只是将有关信息显示给用户,清除进程句柄,然后继续循环,直到所有进程都计算过为止。
在“命令提示符”窗口运行CL.EXE,产生1-3.EXE文件:
C:
\>CL1-3.cpp
运行结果:
第二部分:
进程的“一生”
1、创建进程
创建子进程
//proccreate项目
#include
#include
#include
//创建传递过来的进程的克隆过程并赋于其ID值
voidStartClone(intnCloneID)
{
//提取用于当前可执行文件的文件名
TCHARszFilename[MAX_PATH];
:
:
GetModuleFileName(NULL,szFilename,MAX_PATH);
//格式化用于子进程的命令行并通知其EXE文件名和克隆ID
TCHARszCmdLine[MAX_PATH];
:
:
sprintf(szCmdLine,“\”%s\”%d”,szFilename,nCloneID);
//用于子进程的STARTUPINFO结构
STARTUPINFOsi;
:
:
ZeroMemory(reinterpret_cast(&si),sizeof(si));
si.cb=sizeof(si);//必须是本结构的大小
//返回的用于子进程的进程信息
PROCESS_INFORMATIONpi;
//利用同样的可执行文件和命令行创建进程,并赋于其子进程的性质
BOOLbCreateOK=:
:
CreateProcess(
szFilename,//产生这个EXE的应用程序的名称
szCmdLine,//告诉其行为像一个子进程的标志
NULL,//缺省的进程安全性
NULL,//缺省的线程安全性
FALSE,//不继承句柄
CREATE_NEW_CONSOLE,//使用新的控制台
NULL,//新的环境
NULL,//当前目录
&si,//启动信息
&pi);//返回的进程信息
//对子进程释放引用
if(bCreateOK)
{
:
:
CloseHandle(pi.hProcess);
:
:
CloseHandle(pi.hThread);
}
}
intmain(intargc,char*argv[])
{
//确定进程在列表中的位置
intnClone(0);
if(argc>1)
{
//从第二个参数中提取克隆ID
:
:
sscanf(argv[1],“%d”,&nClone);
}
//显示进程位置
std:
:
cout<<“ProcessID:
“<<:
:
GetCurrentProcessId()
<<“,CloneID:
“<<:
endl;
//检查是否有创建子进程的需要
constintc_nCloneMax=25;
if(nClone{
//发送新进程的命令行和克隆号
StartClone(++nClone);
}
//在终止之前暂停一下(l/2秒)
:
:
Sleep(500);
return0;
}
本程序展示的是一个简单的使用CreateProcess()API函数的例子。
首先形成简单的命令行,提供当前的EXE文件的指定文件名和代表生成克隆进程的号码。
大多数参数都可取缺省值,但是创建标志参数使用了:
___CREATE_NEW_CONSOLE______________________________________________________________________
标志,指示新进程分配它自己的控制台,这使得运行示例程序时,在任务栏上产生许多活动标记。
然后该克隆进程的创建方法关闭传递过来的句柄并返回main()函数。
在关闭程序之前,每一进程的执行主线程暂停一下,以便让用户看到其中的至少一个窗口。
CreateProcess()函数有_____10___个核心参数?
本实验程序中设置的各个参数的值是:
a.__________szFilename_______________________________________;
b.__________szCmdLine_______________________________________;
c.__________NULL_______________________________________;
d._________FALSE________________________________________;
e.__________CREATE_NEW_CONSO_______________________________________;
程序运行时屏幕显示的信息是:
_
正在运行的进程
使用进程和操作系统的版本信息
//version项目
#include
#include
//利用进程和操作系统的版本信息的简单示例
voidmain()
{
//提取这个进程的ID号
DWORDdwIdThis=:
:
GetCurrentProcessId();
//获得这一进程和报告所需的版本,也可以发送0以便指明这一进程
DWORDdwVerReq=:
:
GetProcessVersion(dwIdThis);
WORDwMajorReq=(WORD)(dwVerReq>16);
WORDwMinorReq=(WORD)(dwVerReq&0xffff);
std:
:
cout<<"ProcessID:
"<<<",requiresOS:
"<:
endl;
//设置版本信息的数据结构,以便保存操作系统的版本信息
OSVERSIONINFOEXosvix;
:
:
ZeroMemory(&osvix,sizeof(osvix));
osvix.dwOSVersionInfoSize=sizeof(osvix);
//提取版本信息和报告
:
:
GetVersionEx(reinterpret_cast(&osvix));
std:
:
cout<<"RunningonOS:
"<<:
endl;
//如果是NTS(Windows2000)系统,则提高其优先权
if(osvix.dwPlatformId==VER_PLATFORM_WIN32_NT&&
osvix.dwMajorVersion>=5)
{
//改变优先级
:
:
SetPriorityClass(
:
:
GetCurrentProcess(),//利用这一进程
HIGH_PRIORITY_CLASS);//改变为high
//报告给用户
std:
:
cout<<"TaskManagershouldnownowindicatethis"
"processishighpriority."<:
endl;
}
}
运行结果:
当前PID信息:
____8021__________________________________________________
当前操作系统版本:
___6.1_______________________________________________
系统提示信息:
_TaskManagershouldnownowindicatethisprocessishighpriority.
程序向读者表明了如何获得当前的PID和所需的进程版本信息。
为了运行这一程序,系统处理了所有的版本不兼容问题。
接着,程序演示了如何使用GetVersionEx()API函数来提取OSVERSIONINFOEX结构。
这一数据块中包括了操作系统的版本信息。
其中,“OS:
5.0”表示当前运行的操作系统是:
______________Microsofwindows20005.0________________________________________________
最后一段程序利用了操作系统的版本信息,以确认运行的是Windows2000。
代码接着将当前进程的优先级提高到比正常级别高。
单击Ctrl+Alt+Del键,进入“Windows任务管理器”,在“应用程序”选项卡中右键单击本任务,在快捷菜单中选择“转到进程”命令。
在“Windows任务管理器”的“进程”选项卡中,与本任务对应的进程映像名称是(为什么?
):
_________vcspawn.exe____________________________________________
右键单击该进程名,在快捷菜单中选择“设置优先级”命令,可以调整该进程的优先级,如设置为“高”后重新运行程序,屏幕显示有变化吗?
为什么?
无,PID与优先级无关
终止进程
指令其子进程来“杀掉”自己的父进程
//procterm项目
#include
#include
#include
staticLPCTSTRg_szMutexName="w2kdg.ProcTerm.mutex.Suicide";
//创建当前进程的克隆进程的简单方法
voidStartClone()
{
//提取当前可执行文件的文件名
TCHARszFilename[MAX_PATH];
:
:
GetModuleFileName(NULL,szFilename,MAX_PATH);
//格式化用于子进程的命令行,指明它是一个EXE文件和子进程
TCHARszCmdLine[MAX_PATH];
:
:
sprintf(szCmdLine,"\"%s\"child",szFilename);
//子进程的启动信息结构
STARTUPINFOsi;
:
:
ZeroMemory(reinterpret_cast(&si),sizeof(si));
si.cb=sizeof