操作系统试验指导书2023春季学期_第1页
操作系统试验指导书2023春季学期_第2页
操作系统试验指导书2023春季学期_第3页
操作系统试验指导书2023春季学期_第4页
操作系统试验指导书2023春季学期_第5页
已阅读5页,还剩67页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

本文格式为Word版,下载可任意编辑——操作系统试验指导书2023春季学期

操作系统试验指导书

计算机科学与软件学院

2023年

试验一进程控制与描述

一、试验目的

通过对WindowsXP编程,进一步熟悉操作系统的基本概念,较好地理解WindowsXP的结构。通过创立进程、观测正在运行的进程和终止进程的程序设计和调试操作,进一步熟悉操作系统的进程概念,理解WindowsXP进程的“一生〞。

二、试验环境

硬件环境:计算机一台,局域网环境;

软件环境:WindowsXP,VisualC++6.0专业版或企业版。三、试验内容和步骤

第一部分Windows编程

WindowsXP可以识别的程序包括控制台应用程序、GUI应用程序和服务应用程序。本试验中主要用到的是控制台应用程序和GUI应用程序。

1、简单的控制台应用程序

创立一个名为“Hello〞的应用程序,在“开始〞菜单中单击“程序〞-“附件〞-“记事本〞命令,将程序键入记事本中,并把代码保存为1-1.cpp。

程序1-1WindowsXP的GUI应用程序#includevoidmain(){

Std::coutCL1-1.cpp

运行1-1.EXE程序,运行结果是:(假使运行不成功,则可能的原因是什么?)

________________________________________________________________________________________________________________________________________2、GUI应用程序

WindowsXPProfessional下的GUI应用程序,使用VisualC++编译器创立一个GUI应用程序,代码中包括了WinMain()方法,该方法GUI类型的应用程序的标准入口点。

在“开始〞菜单中单击“程序〞-“附件〞-“记事本〞命令,将程序键入记事本中,并把代码保存为1-2.cpp。

程序1-2WindowsXP的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-2.EXE文件:C:\\>CL1-2.cpp

在程序1-2的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。

运行结果(试将其中的信息与程序1-1.EXE的运行结果进行比较):

_____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

3、进程对象

操作系统将当前运行的应用程序看作是进程对象。利用系统提供的惟一的称为句柄(HANDLE)的号码,就可与进程对象交互。这一号码只对当前进程有效。

本试验表示了一个简单的进程句柄的应用。在系统中运行的任何进程都可调用GetCurrentProcess()API函数,此函数可返回标识进程本身的句柄。然后就可在Windows需要该进程的有关状况时,利用这一句柄来提供。

程序1-3:获得和使用进程的句柄

//prochandle项目#include#include

//确定自己的优先权的简单应用程序voidmain(){

//从当前进程中提取句柄

HANDLEhProcessThis=::GetCurrentProcess();

//请求内核提供该进程所属的优先权类

DWORDdwPriority=::GetPriorityClass(hProcessThis);

//发出消息,为用户描述该类

std::cout〞;break;}

std::coutCL1-3.cpp

运行结果:__________________________________________________________________________________________________________________________________________________________________________________________________________

将程序1-4.cpp程序键入记事本中,并把代码保存为1-4.cpp。程序1-4显示如何找出系统中正在运行的所有进程,如何利用OpenProcess()API函数来获得每一个访问进程的进一步信息。

程序1-4利用句柄查出进程的详细信息//proclist项目

#include#include#include

//当在用户模式机内核模式下都提供所耗时间时,在内核模式下进行所耗时间的64位计算的帮助方法DWORDGetKernelModePercentage(constFILETIMEULONGLONGqwUser=

(((ULONGLONG)ftUser.dwHighDateTime)CL1-4.cpp

运行结果:__________________________________________________________________________________________________________________________________

l}else{

Parent();}

return0;}

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

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

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

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

运行结果:

1)__________________________________________________________________表示:______________________________________________________________2)__________________________________________________________________表示:______________________________________________________________

在熟悉源代码的基础上,利用本试验介绍的API函数来尝试改进本程序(例如使用GetProcessTimes()API函数)并运行。请描述你所做的工作:

____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

四、试验总结

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

试验二并发与调度

一、试验目的

在本试验中,通过对事件和互斥体对象的了解,来加深对WindowsXP线程同步的理解。通过分析试验程序,了解管理事件对象的API。了解在进程中如何使用事件对象,在进程中如何使用互斥体对象,线程如何通过文件映射对象发送数据。

二、试验环境

硬件环境:计算机一台,局域网环境;

软件环境:WindowsXPProfessional,VisualC++6.0专业版或企业版。三、试验内容和步骤第一部分:互斥体对象

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

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

//mutex项目

#include#include

//利用互斥体来保护同时访问的共享资源classCCountUpDown{

public:

//创立者创立两个线程来访问共享值CCountUpDown(intnAccesses):m_hThreadlnc(INVALID_HANDLE_VALUE),m_hThreadDec(INVALID_HANDLE_VALUE),m_hMutexValue(INVALID_HANDLE_VALUE),m_nValue(0),

m_nAccess(nAccesses){

//创立互斥体用于访问数值m_hMutexValue=::CreateMutex(NULL,//缺省的安全性TRUE,//初始时拥有,在所有的初始化终止时将释放NULL);//匿名的m_hThreadInc=::CreateThread(NULL,//缺省的安全性0,//缺省堆栈IncThreadProc,//类线程进程reinterpret_cast(this),//线程参数0,//无特别的标志NULL);//忽略返回的idm_hThreadDec=::CreateThread(NULL,//缺省的安全性0,//缺省堆栈DecThreadProc,//类线程进程reinterpret_cast(this),//线程参数0,//无特别的标志NULL);//忽略返回的id//允许另一线程获得互斥体

::ReleaseMutex(m_hMutexValue);}

//解除程序释放对对象的引用

virtual~CCountUpDown()

{

::CloseHandle(m_hThreadInc);::CloseHandle(m_hThreadDec);::CloseHandle(m_hMutexValue);}

//简单的等待方法,在两个线程终止之前可暂停主调者virtualvoidWaitForCompletion(){

//确保所有对象都已准备好if(m_hThreadInc!=INVALID_HANDLE_VALUE::WaitForSingleObject(m_hThreadDec,INFINITE);}}

protected:

//改变共享资源的简单的方法virtualvoidDoCount(intnStep){

//循环,直到所有的访问都终止为止while(m_nAccess>0){

//等待访问数值

::WaitForSingleObject(m_hMutexValue,INFINITE);//改变并显示该值m_nValue+=nStep;

std::cout(lpParam);

//调用对象的增加方法并返回一个值

pThis->DoCount(+1);return(0);}

staticDWORDWINAPIDecThreadProc(LPVOIDlpParam){

//将参数解释为?this?指针CCountUpDown*pThis=

reinterpret_cast(lpParam);//调用对象的减少方法并返回一个值pThis->DOCount(-1);return(0);}

protected:

HANDLEm_hThreadInc;HANDLEm_hThreadDec;HANDLEm_hMutexValue;intm_nValue;intm_nAccess;

};

voidmain()

{

CCountUpDownud(50);ud.WaitForCompletion();}

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

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

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

其次部分线程通过文件对象发送数据

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

1、演示线程通过文件对象发送数据

下边程序代码展示了线程如何通过文件对象在永久存储介质上相互发送数据。程序只是激活并启动了一个线程接着一个线程的创立线程。每个线程从指定的文件中读取数据,并对数据进行修改,其修改增量是以创立时发送给它的数量进行的,然后将新数值写回文件。

#inc1ude#include//要使用的文件名

staticLPCTSTRg_szFileName=“w2kdg.Fileobj.file.data.txt〞;

//在数据文件中读取当前数据的简单线程时将传递来的该数据增加,并写回数据文件中staticDWORDWINAPIThreadProc(LPVOIDlpParam){

//将参数翻译为长整数

LONGnAdd=reinterpret_cast(lpParam);//建立完全的指定文件名(包括路径信息)TCHARszFullName[MAX_PATH];

::GetTempPath(MAX_PATH,szFullName);//取得路径::strcat(szFullName,g_szFileName);//开启文件对象

HANDLEhFile=::CreateFile(szFullName,//文件的完全名称GENERIC-READ|GENERIC_WRITE,//具有所有的访问权FILE_SHARE_READ,//允许其他线程读取NULL,//缺省的安全性OPEN_ALWAYS,//创立或开启文件FILE_ATTRIBUTE_NORMAL,//普通文件NULL);//无模板文件if(hFile!=INVALID_HANDLE_VALUE){

//读取当前数据LONGnValue(0);DWORDdwXfer(0);::ReadFile(hFile,//要读取的文件reinterpret_cast(//无重叠I/O

if(dwXfer==sizeof(nValue))

{std::cout(//无重叠I/O

if(dwXfer==sizeof(nValue))

{std::cout0;--nTotal)

{

//启动线程

HANDLEhThread=::CreateThread(

NULL,//缺省的安全性0,//缺省的堆栈ThreadProc,//线程函数reinterpret_cast(1),//增量0,//无特别的创立标志

NULL);//忽略线程id//等待线程完成

::WaitForSingleObject(hThread,INFINITE);

::Sleep(500);//放慢显示速度,便利观测//释放指向线程的句柄::CloseHandle(hThread);hThread=INVALID_HANDLE_VALUE;

}}

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

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

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

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

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

____________________________________________________________________________________________________________________________________________

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

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

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

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

____________________________________________________________________________________________________________________________________________

2、演示使用映射文件的内存交换数据的线程

#include#include//仲裁访问的互斥体

staticHANDLEg_hMutexMapping=INVALID_HANDLE_VALUE;//增加共享内存中的数值的简单线程

staticDWORDWINAPIThreadProc(LPVOIDlpParam){

//将参数看作句柄

HANDLEhMapping=reinterpret_cast(IpParam);

//等待对文件的访问

::WaitForSingleObject(g_hMutexMapping,INFINITE);//映射视图

LPVOIDpFile=::MapViewOfFile(hMapping,//保存文件的对象FILE_MAP_ALL_ACCESS,//获得读写权限0,//在文件的开头处(高32位)开始0,//...(低32位)0);//映射整个文件if(pFile!=NULL){

//将数据看作长整数

LONG*pnData=reinterpret_cast(pFile);//改动数据++(*pnData);//显示新数值

std::cout

if(pData!=NULL){::ZeroMemory(pData,sizeof(LONG));}

//关闭文件视图

::UnmapViewOfFile(pData);}

return(hMapping);}

voidmain(){

//创立数据文件

HANDLEhMapping=::MakeSharedFile();//创立仲裁的互斥体

g_hMutexMapping=::CreateMutex(NULL,FALSE,NULL);//根据文件创立100个线程来读写

for(intnTotal=100;nTotal>0;--nTotal){

//启动线程

HANDLEhThread=::CreateThread(NULL,//缺省的安全性0,//缺省堆栈ThreadProc,//线程函数reinterpret_cast(hMapping),//增量0,//无特别的创立标志NULL);//忽略线程id//等待最终的线程释放if(nTotal==l){std::cout#include#include#include

#pragmacomment(lib,\

//以可读方式对用户显示保护的辅助方法。

//保护标记表示允许应用程序对内存进行访问的类型//以及操作系统强制访问的类型

inlineboolTestSet(DWORDdwTarget,DWORDdwMask){

return((dwTarget}

#defineSHOWMASK(dwTarget,type)\\if(TestSet(dwTarget,PAGE_##type))\\{std::cout0)//实际使用的缓冲区大小

{//除去路径并显示::PathStripPath(szFilename);std::coutCommitted,READWRITE,Private

可描述为:具有READWRITE权限的已调配私有内存区。

将系统当前的自由区(free)虚拟地址空间填入表中。

地址大小虚拟地址空间类型freefreefreefreefree访问权限描述

将系统当前的已调配区(committed)虚拟地址空间填入表中。地址大小虚拟地址空间类型committedcommittedcommittedcommittedcommitted访问权限描述

将系统当前的保存区(reserved)虚拟地址空间填入表5-8中。地址大小虚拟地址空间类型reservedreservedreservedreservedreserved访问权限描述

2)从上述输出结果,对照分析程序,请简单描述程序运行的流程:

____________________________________________________________________________________________________________________________________________2.虚拟内存操作

例如程序显示了如何分派一个大容量空间,将物理存储委托给其中的很小一部分(千分之一)并加以使用。

分派和使用大块内存

//工程largealloc

#include#include

//尝试以指定长度的零数字填充内存块的简便方法voidFillZero(LPVOIDpBlock,DWORDdwSize){

_try{

BYTE*arFill=(BYTE*)pBlock;

for(DWORDdwFill=0;dwFill

____________________________________________________________________3)输入命令,显示practice目录中文件和目录的长列表。创立的目录列出来了吗?____________________________________________________________________4)目录的所有者是?

____________________________________________________________________5)文件的大小是多少?

____________________________________________________________________6)使用file命令确定newdir文件的类型。它是哪一类的文件?

____________________________________________________________________7)假使名字中没有字符dir,采取别的什么方法来识别出它是一个目录?

____________________________________________________________________8)mkdir命令创立3个目录,目录名分别为high、medium和low,应当使用什么命令?____________________________________________________________________9)用ls命令检查创立是否成功?步骤17:使用rm命令删除文件。

rm目录可以删除单个文件或多个文件。可以通过在rm命令之后指定文件的名字,或者使用星号(*)和问号(?)元字符,同时删除几个文件。在Linux系统中删除的文件是永远被删除了,除非使用图形界面删除文件,它们才能够被恢复。rm命令可以带–i(交互)选项使用,它在删除文件之前会提醒用户。使用rm-i命令作为防范,避免误删文件:

rm[-i]filename(s)

1)使用rm命令删除早先在practice目录中创立的newfile文件,应当使用什么命令?____________________________________________________________________2)输入命令显示practice目录中文件的长列表。创立的文件还在吗?

____________________________________________________________________

3)使用带-i选项的rm命令,删除早先在practice目录中创立的filenew文件。交互式选项起到什么作用?

____________________________________________________________________

4)删除早先创立的三个名为new1、new2和new3的文件。使用问号(?)通配符使用一个命令删除所有三个文件。使用什么命令?

____________________________________________________________________5)输入命令,显示practice目录中文件的长列表。三个文件还在吗?

____________________________________________________________________6)还有其他的什么方法来删除new1、new2和new3文件?

____________________________________________________________________步骤18:使用rm-r命令删除目录。

rm-r目录用于删除目录。它将删除从目标目录开始的目录,包括所有的子目录和文件。当rm命令带-r信息使用的时候,它可以删除单个目录(空或不空)或目录树的整节。rm命令可以带-i选项使用,它在删除目录之前会提醒用户:

rm–r[i]directory_name(s)

1)删除早先创立的newdir子目录,使用什么命令?

____________________________________________________________________2)输入命令显示practice目录中文件的长列表,创立的子目录还在吗?

____________________________________________________________________3)改变到早先创立的mediurn子目录中,输入什么命令?

____________________________________________________________________4)删除早先创立的low子目录,使用什么命令?

____________________________________________________________________5)用相对路径名和快捷方式,改变回到practice子目录中,应使用什么命令?

____________________________________________________________________6)使用一个命令删除high和medium子目录,应使用什么命令?

____________________________________________________________________步骤19:练习所学习到的内容。

通过在practice目录中创立一个三级的目录树,练习使用touch、mkdir和rm命令。试着使

用有意义的目录名。记住可以使用一个命令创立整个目录结构。在每个目录中创立多个文件。记住可以使用一个命令创立多个文件。

终止的时候,请删除试验时创立的文件和目录。步骤20:关闭终端窗口,注销。

四、试验总结

请总结一下本次试验的收获、教训和感受,结合Windows操作系统的相关内容谈一下你对

Linux文件操作命令的理解。

//使用虚拟分派以获得虚拟1GB块{

LPVOIDpBlock=::VirtualAlloc(NULL,//不指定起始地址c_dwGigabyte,//要求1GBMEM_RESERVE,//不调配物理存储PAGE_READWRITE);//对此的读写操作::FillZero(pBlock,c_dwMegabyte);

::VirtualFree(pBlock,0,MEM_RELEASE);}

//使用虚拟分派调配获得虚拟1GB块,再为其调配1MB物理存储{

LPVOIDpBlock=::VirtualAlloc(NULL,//不指定起始地址c_dwGigabyte,//要求1GBMEM_RESERVE,//不调配物理存储PAGE_READWRITE);//对此的读写操作::VirtualAlloc(pBlock,c_dwMegabyte,MEM_COMMIT,PAGE_READWRITE);

::FillZero(pBlock,c_dwMegabyte);

::VirtualFree(pBlock,0,MEM_RELEASE);}}

对照运行结果,分析程序。为了给数据库保存1GB的段地址空间,程序给出了内存分派的四种方法。

·第一种技术

即程序中说明为___________________________________________________的程序段,该段程序试图利用标准C中的malloc()函数,从已经已调配的小内存区获得内存。从运行结果看,这种技术成功了吗?_____________________。

·其次种技术

即程序中说明为___________________________________________________的程序段,该段程序试图通过VirtualAlloc(),然后利用物理备用内存将整个块分派到虚拟内存空间的任何位置。这种技术只对拥有1GB以上的RAM且都有换页文件的计算机可行。从运行结果看,这种技术成功了吗?_____________________。

·第三种技术

即程序中说明为___________________________________________________的程序段,该段程序利用VirtualAlloc(),假使函数成功,则获得大块内存,但不将任何物理内存调配到此块中。从运行结果看,这种技术成功了吗?_________________。

·第四种技术

即程序中说明为___________________________________________________的程序段,该段程序保存1GB的内存区,然后将物理内存调配给其中的很小一部分(1MB)。这就是程序介绍的处理一个假想的数据库应用程序的方法:保存整个块,然后按要求在其一小部分内进行读操作,让系统将用过的区域换页到磁盘中。

利用VirtualLock()API,Windows可用来在自己的进程空间中控制虚拟内存的行为。这个函数与其成对的VirtualUnlock()阻止或允许一块内存从物理RAM中换页和换页到页面文件中。这样就会通知系统有一段特定的内存区要求对用户作出猛烈的响应,所以系统不应将其移出RAM。当然,假使要将整个虚拟内存空间锁定,系统就会停留于试图将系统中工作内存的每一小块换页到磁盘

3.虚拟内存的分派与释放

能正确使用系统函数GetMeoryStatus()和数据结构MEMORY_STATUS了解系统内存和虚拟存储空间使用状况,会使用VirsualAlloc()函数和VirsualFree()函数分派和释放虚拟内存空间。

//GetMemoryStatus.cpp:Definestheentrypointfortheconsoleapplication.

//

#include\

#include\

#ifdef_DEBUG

#definenewDEBUG_NEW#undefTHIS_FILE

staticcharTHIS_FILE[]=__FILE__;#endif

voidGetMemSta(void);

//TheoneandonlyapplicationobjectCWinApptheApp;usingnamespacestd;

int_tmain(intargc,TCHAR*argv[],TCHAR*envp[]){

intnRetCode=0;LPVOIDBaseAddr;char*str;

GetMemSta();

printf(\

BaseAddr=::VirtualAlloc(NULL,1024*1024*32,MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE);//分派虚拟内存

if(BaseAddr==NULL)printf(\

str=(char*)malloc(1024*1024*2);//分派内存GetMemSta();printf(\

if(::VirtualFree(BaseAddr,0,MEM_RELEASE)==0)//释放虚拟内存printf(\

free(str);//释放内存

GetMemSta();returnnRetCode;

}

voidGetMemSta(void){

MEMORYSTATUSMemInfo;GlobalMemoryStatus(

printf(\

printf(\printf(\vailablePhysicalMemoryis%dMB\\n\vailPhys/(1024*1024));printf(\printf(\vailablePageFileis%dMB\\n\vailPageFile/(1024*1024));printf(\printf(\vailableVirsualmemoryis%dMB\\n\vailVirtual/(1024*1024));printf(\

}

步骤1:在VC6.0环境下选择Win32ConsoleApplication建立一个控制台工程文件,选择AnapplicationthatSupportsMFC。

步骤2:编辑并编译完成后,单击“Build〞菜单中的“BuildGetMemoryStatus.exe〞命令,建立GetMemoryStatus.exe可执行文件。

操作能否正常进行?假使不行,则可能的原因是什么?

____________________________________________________________________________________________________________________________________________步骤3:在工具栏单击“ExecuteProgram〞按钮,执行GetMemoryStatus.cpp.exe程序。分析程序GetMemoryStatus.cpp的运行结果

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

________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

2)根据运行输出结果,若要改变分派和回收的虚拟内存和物理内存的大小,要改变程序代码的语句,分别为:

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

其次部分Linux用户程序的内存管理

现代操作系统允大量个程序同时运行,因此,内存中需要同时存放这些程序。操作系统采用的存储管理方案主要有分区式存储管理、分页式存储管理、分段式存储管理和段页式存储管理等。本试验以一个Linux实例程序说明应用程序如何通过系统调用来管理自己用的空闲内存,目的在于了解用户程序分派内存以及回收所用内存的程序过程,加深对操作系统存储管理机制的理解。本试验实例由my-malloc.h、my-malloc.c和test.c三个文件组成。为阅读程序便利,对其中的主要函数作了说明,同学们可结合程序解释理解该程序。

本试验程序主要定义了一个描述自由存储块的结构,每一个自由块都包含块的大小、指向下一块的指针以及块区本身,所有的自由块以地址增加顺序排列,并用链表链接起来。这一链表是本程序维护的一个空闲区域,对于操作系统的当前记录来说是已分出去的区域。由于本程序是运行在用户态的程序。

步骤1:单击红帽子,在“GNOME帮助〞菜单中单击“附件〞-“文本编辑器〞命令,在文本编辑中键入清单5-4程序并保存为my-malloc.h。

清单5-4my-malloc.h文件

#includetypedeflongAlign;unionheader{struct{

/*foralignmenttolongboundary*//*blockheader:*/

/*nextblockifonFreelist*//*sizeofthisblock*//*forcealignmentofblocks*/

unionheader*next;unsignedintsize;}s;Alignx;};

typedefunionheaderHeader;

#defineNALLOC10/*minimum#unitstorequest*/staticHeader*morecore(unsignedintnu);void*Malloc(unsignedintnbytes);voidFree(void*ap);

步骤2:单击红帽子,在“GNOME帮助〞菜单中单击“附件〞-“文本编辑器〞命令,在文本编辑中键入清单5-5程序并保存为my-malloc.c。

清单5-5my-malloc.c文件#include#include“my_malloc.h〞staticHeaderbase;staticHeader*free_list=NULL;

/*empylisttogetstarted*//*startoffreelist*/

/*Malloc:general-purposestorageallocator*/void*Malloc(unsignedintnbytes)

{

Header*p,*prev;unsignedintnunits;

nunits=(nbytes+sizeof(Header)-1)/sizeof(Header)+1;if((prev=free_list)==NULL){

/*nofreelistyet*/

base.s.next=free_list=prev=base.s.size=0;}

for(p=prev->s.next;;prev=p,p=p->s.next){if(p->s.size>=nunits){if(p->s.size==nunits)

/*bigenough*//*exactly*/

prev->s.next=p->s.next;else{

p->s.size-=nunits;p+=p->s.size;p->s.size=nunits;}free_list=prev;return(void*)(p+1);}

if(p==free_list)/*wrappedaroundFreelist*/if((p=morecore(nunits))==NULL)returnNULL;/*noneleft*/}}

/*endfor*/

/*morecore:asksystemformorememory*/staticHeader*morecore(unsignedintnu){

char*cp;Header*up;

if(nus.size=nu;Free(up+1);returnfree_list;}

/*Free:putblockapinFreelist*/voidFree(void*ap){

Header*bp,*p;

bp=(Header*)ap–1;

/*nospaceatall*/

/*pointtoblockheader*/

for(p=free_list;!(bp>pp=p->s.next)

if(p>=p->s.next/*freedblockatstartorendofarena*/if(bp+bp->s.size==p->s.next){/*jointouppernbr*/bp->s.

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论