高级系统程序设计.doc

上传人:仙人指路1688 文档编号:2386176 上传时间:2023-02-17 格式:DOC 页数:17 大小:111KB
返回 下载 相关 举报
高级系统程序设计.doc_第1页
第1页 / 共17页
高级系统程序设计.doc_第2页
第2页 / 共17页
高级系统程序设计.doc_第3页
第3页 / 共17页
高级系统程序设计.doc_第4页
第4页 / 共17页
高级系统程序设计.doc_第5页
第5页 / 共17页
点击查看更多>>
资源描述

《高级系统程序设计.doc》由会员分享,可在线阅读,更多相关《高级系统程序设计.doc(17页珍藏版)》请在三一办公上搜索。

1、重庆科技学院高级系统程序设计大作业专业班级: 学 号: 姓 名: 成 绩: 摘 要在windows API中,有自己独特的I/O操作,与C/C+中的I/O操作有何种区别;并且windows中的内核对象是怎样定义的,具体是怎样操作。Windows有自己的内存架构,根据特定的要求有不同的管理内存方法,其中堆适合大量的小对象,然而内存映射文件适合大文件,各自具有不同的特性。关键字:I/O 内核对象 堆 内存映射文件目 录公共部分11.1请综合比较C/C+中I/O的使用方法与本课程程序实践中所采用的I/O方法各自的特点,并请举例分析说明?11.1.1 C/C+ I/O11.1.2Windows I/O

2、21.1.3总体区别31.2基本请结合具体的例子解释什么是内核对象,对内核对象的操作与之前学习的对指针的操作方法有什么本质的区别?31.2.1windows中的内核对象31.2.2内核对象与指针的区别4选题部分52.1windows内存管理构架52.2内存映射文件52.2.1怎样使用内存映射文件52.2.2内存映射文件的使用特点62.3堆92.3.1使用堆92.3.2堆的使用特点103.总结12参考文献13致谢14公共部分1.1请综合比较C/C+中I/O的使用方法与本课程程序实践中所采用的I/O方法各自的特点,并请举例分析说明?1.1.1 C/C+ I/O1)用标准库,通过调用函数实现标准输入

3、,输出C/C+的输入/输出由标准库提供。标准库定义了一族类型,支持对文件和控制窗口等设备的读写。而且在C+中还新定义了I/O流,在C语言中,标准库stdio.h提供了两个控制台格式化输入、输出函数printf()和scanf(),这两个函数可以在标准输入输出设备上以各种不同的格式读写数据。printf()函数用来向标准输出设备(屏幕)写数据,具体格式为printf(,);scanf()函数用来从标准输入,具体格式为:scanf(,);例如:输入:printf(”hahahahahan”);输出:scanf(“%d”,&a);在C+中,I/O流是一系列写到屏幕上或从键盘上读出的字节序列。将I/O

4、流定义为类,执行标准的输入输出操作时,一般使用I/O流cin作为输入,cout作为输出。在ios.h、iostream.h、istream.h、ostream.h以及streamb.h中可以找到I/O流的定义。iostream.h中定义了如下四个对象:cin键盘输入(stdin)、cout屏幕输出(stdout)、cerr标准错误设备输出(stderr)、clog标准错误缓冲输出(stderr)。例如:cinname;cout”Helllo World!”;cerr”Error!”;clog 0) WriteFile (hOut, buffer, nIn, &nOut, NULL);关闭文件句

5、柄CloseHandle (hIn); CloseHandle (hOut);1.2.2内核对象与指针的区别实例中,文件对象是windows中的内核对象,我们只能调用windows提供的API函数进行文件操作,事实上我们也只能通过文件句柄进行操作,除此之外没有其它的办法。但是在C/C+中,将对象的地址作为数据,也就是指针值,用于保存地址的变量就是指针。也就是通过指针访问内存,进行内存中数据的修改。我们只要知道了内存地址,就可以通过指针对该内存进行修改。然而windows中的内核对象,我们只能通过API函数,得到句柄进行相关的操作而且windows中为了对象的安全,支持广泛的安全模型,能够防止对

6、诸如文件、进程等对象的未经授权的访问,其中几乎所有可共享的对象都可以得到保护。例如:windows中,在创建文件时,第四个参数,LPSECURITY_ATTRIBUTES lpSecurityAttributes,就是说明了对象的安全属性。所以,指针与内核对象的本质区别就是,指针可以对内存进行任意的修改,而且指针可以我们根据自己的需要进行定义。内核对象只能通过句柄对相关的地方进行操作,而且有严格的对象安全属性,只能根据需要调用API函数,不能自己定义!选题部分题目一:综合比较Windows内存管理中内存映射文件和堆2钟方法各自的特点,写出你的详细分析结论并请编程举例说明,必须在大作业中给出你的

7、每个程序的设计思考过程和关键程序代码段,完整的源程序可在附录中给出。 2.1windows内存管理构架 Windows程序C库:malloc,free MMF API (内存映射文件) 堆API 虚拟内存API 带有虚拟内存管理器的Windows内核物理内存磁盘和文件系统2.2内存映射文件内存映射文件的物理存储器来自磁盘上已有的文件,而不是来自系统的页面交换文件,一旦把文件映射到地址空间,我们就可以对他进行访问,就好像将整个文件已经载入内存一样。2.2.1怎样使用内存映射文件1)打开文件2)如果是新文件,那么要使用CreateFileMapping,要么先使用SetFilepointerEx,

8、然后使用SetEndOfFile来设置长度。3) 使用CreateFileMapping或OpenFileMapping来映射文件4) 使用MapViewOFile创建一个或多个视图5) 通过内存引用来访问文件6)完成后,关闭有关句柄涉及的有关函数:创建一个带有句柄的文件映射对象HANDLE CreateFileMapping(HANDLE hFile, /物理文件句柄LPSECURITY_ATTRIBUTES lpsa, /安全设置DWORD dwProtect, /保护设置DWORD dwMaximumSizeHigh, /高位文件大小DWORD dwMaximumSizeLow, /低位

9、文件大小LPCTSTR lpMapName /共享内存名称);打开现有的文件映射:HANDLE OpenFileMapping(DWORD dwDesiredAccess,/访问权限BOOL bInheritHandle,/ 返回的句柄是否能由当前进程启动的新进程继承LPCTSTR lpMaName/共享内存名称)将对象映射到地址空间LPVOID MapViewOfFile( HANDLEhMapObject,/ 文件映射对象的句柄 DWORDdwAccess,/访问权限 DWORDdwOffsetHigh,/ 文件中映射起点的高32位地址DWORDdwOffsetLow,/文件中映射起点的低

10、32位地址 SIZE_T cbMap/以字节为单位的映射区域尺寸值);关闭映射句柄BOOL UnmapViewOfFile(LPVOID lpBaseAddress)2.2.2内存映射文件的使用特点1)系统使用内存映射文件,以便加载和执行.exe和DLL文件。大大节省页文件空间和应用程序启动运行所需的时间。当一个程序在调用CreateProcess的时候,系统首先就会先确定创建进程时所指定的可执行文件的位置,如果找不到创建进程就会失败;找到了可执行文件的位置,系统就会创建一个新的进程内核对象,并为他创建一个私有的地址空间。而且系统会预定一块足够大的地址空间来容纳可执行文件并且系统会对地址空间区

11、域进行标注说明该区域来自磁盘上的可执行文件,也就是将可执行文件映射到虚拟地址空间,这样就可以节省页文件空间。当系统把可执行文件映射到进程的地址空间后,就会访问可执行文件中一个段,这个段列出了一些DLL文件,他们包含了可执行文件的需要调用的函数。同样系统会把用到的DLL也映射到一块足够大的地址空间并标注。把所有的可执行文件和DLL文件都映射到进程的地址空间后,系统就会开始执行可执行文件的启动代码。由于采取的文件映射,时间较短,就不用一段一段的将指令读入内存,所以也就节省了程序的启动运行时间。2)开发人员使用内存映射文件来访问磁盘上的数据文件。这样可以避免直接对文件执行I/O操作和对文件内容进行缓

12、存,并且可以进行大文件操作。由于使用内存映射文件,是将来自磁盘上已有的文件映射到地址空间,所以肯定就可以避免直接对文件执行I/O操作和对文件内容进行缓存。例如:将一个文件映射到虚拟内存空间HANDLE hFile = INVALID_HANDLE_VALUE, hMap = NULL;LPVOID pFile = NULL;hFile = CreateFile (tempFile, GENERIC_READ| GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);/打开文件hMap = CreateFileMapping (hFile, NULL, P

13、AGE_READWRITE, 0, 0, NULL);/创建一个内核文件映射对象pFile = MapViewOfFile (hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);/将文件映射到进程的虚拟地址空间UnmapViewOfFile (pFile)/释放视图;CloseHandle (hMap);/关闭文件映射句柄CloseHandle (hFile);/关闭文件句柄在win32 API中,提供有支持文件处理的函数 (如CreateFile()、WriteFile()、ReadFile()等).。一般来说,以上这些函数可以满足大多数场合的要求,但是对于某些超过几个G

14、大文件,再以通常的文件处理方法进行处理显然是行不通的,因为不能一次将文件映像全部映射进来。对于这种情况只能依次将大文件的各个部分映射到进程中的一个较小的地址空间例如:使用内存映射文件进行大文件的操作,由于不能一次性将文件全部映射到地址空间,所以就只能将文件一部分一部分的映射到地址空间,其中最关键的是要分别将每一部分映射到地址空间后,要关闭视图,而且要确定文件偏移的大小,循环映射,直到文件全部映射完成(本程序源于Wndows核心编程第五版)/创建文件HANDLEhFile=CreateFile(“haha”,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXIST

15、ING,FILE_ATTRIBUTE_NORMAL,NULL);/创建文件映射HANDLEhFileMap=CreateFileMapping(hFile,NULL,PAGE_READWRITE,0,0,NULL);/得到系统分配粒度SYSTEM_INFOSysInfo;GetSystemInfo(&SysInfo);DWORDdwGran=SysInfo.dwAllocationGranularity;/得到文件尺寸DWORDdwFileSizeHigh;_int64qwFileSize=GetFileSize(hFile,&dwFileSizeHigh);qwFileSize|=(_int

16、64)dwFileSizeHigh)32);/关闭文件对象CloseHandle(hFile);/偏移地址_int64qwFileOffset=0;/块大小DWORDdwBlockBytes=1000*dwGran;if(qwFileSize0)/映射视图LPBYTElpbMapAddress=(LPBYTE)MapViewOfFile(hFileMap,FILE_MAP_ALL_ACCESS,(DWORD)(qwFileOffset32),(DWORD)(qwFileOffset&0xFFFFFFFF),dwBlockBytes);/对映射的视图进行访问for(DWORDi=0;idwBlo

17、ckBytes;i+)BYTEtemp=*(lpbMapAddress+i);/撤消文件映像UnmapViewOfFile(lpbMapAddress);/修正参数qwFileOffset+=dwBlockBytes;qwFileSize-=dwBlockBytes;/关闭文件映射对象句柄CloseHandle(hFileMap);3)可以使用内存映射文件,使同一台计算机上运行的多个进程能够相互之间共享数据共享内存主要是通过映射机制实现的。Windows下进程的地址空间是相互隔离的,但在物理上却是重叠的。所谓的重叠是指同一块内存区域可能被多个进程同时使用。当调用CreateFileMappin

18、g创建命名的内存映射文件对象时,Windows即在物理内存中申请了一块指定大小的内存区域,返回文件映射对象的新句柄hMap。为了能够访问这块区域必须调MapViewOfiFile函数,促使Windows将此内存空间映射到进程的地址空间中。当在其他进程中访问这块区域时,则必须使用OpenFileMapping函数来取得对象句柄hMap,并调用MapViewOfFile函数得到此内存空间的一个映射。这样一来,系统就把同一块内存区域映射到了不同进程的地址空间中,从而达到共享内存的目的。例如:用C写一个程序,使用内存映射文件进行简单的数据共享。首先,将字符串利用内存映射文件映射到地址空间char Na

19、me = SURE; / 内存映射对象的名称 char Data = abcdefghijk; / 共享内存中的数据 LPVOID pBuffer; / 共享内存指针 HANDLE hMap=CreateFileMapping( INVALID_HANDLE_VALUE,NUPAGE_READWRITE,0, strlen(Data),Name); / 映射对象的一个视图,得到指向共享内存的指针,设置里面的数据 pBuffer = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0); strcpy(char*)pBuffer, Data); pr

20、intf( 写入共享内存数据:%sn, (char*)pBuffer); 然后,打开现有的文件映射使用OpenFileMapping函数来取得对象句柄hin,并调用MapViewOfFile函数得到此内存空间的一个映射 HANDLE hin=OpenFileMapping(FILE_MAP_ALL_ACCESS, 0, Name); if(hin != NULL) / 打开成功,映射对象的一个视图,得到指向共享内存的指针,显示出里面的数据 pBuffer =MapViewOfFile(hin, FILE_MAP_ALL_ACCESS, 0, 0, 0); printf( 读出共享内存数据:%s

21、n, (char*)pBuffer); 2.3堆Windows在堆中维护着内存池,进程可以包含许多堆,我们从堆中分配内存。而且堆是Windows对象,但不是内核对象,在分配内存时需要堆句柄。 堆是进程创建时在进程空间建立的区域,由堆管理器来管理。一个进程可以有很多个堆。进程有一个默认堆,可以动态的扩大。当程序需要管理很多小对象时,适合用堆。2.3.1使用堆一、使用堆常用的函数:1、 获得进程默认堆句柄HANDLE GetProcessHeap(VOID)返回:本进程的堆句柄,失败返回NULL2、 创建堆HANDLE HeapCreate( DWORD flOptions,/创建堆的选项 DWO

22、RD dwInitialSize,/初始大小 DWORD dwMaximumSize/最大尺寸)3、从堆中分配内存块 HeapAllocLPVOIDHeapAlloc(HANDLE hHeap;/分配内存的堆句柄DWORD dwFlags;/分配控制的选项SIZE_T dwBytes/分配内存块的大小) 4、 改变内存块的大小 HeapReAllocLPVOID HeapReAlloc(HANDLE hHeap;/修改堆的句柄DWORD dwFlags;/控制选项LPVOID lpMem;/指定重新分配的内存块SIZE_T dwBytes/新块的大小); 5、释放内存块 HeapFree BO

23、OL HeapFree(HANDLE hHeap;/释放堆的句柄DWORD dwFlags;/控制选项LPVOID lpMem;/指定释放的内存块);6、得到堆的尺寸HeapSize SIZE_T HeapSize(HANDLE hHeap,/堆句柄DWORD dwFlags,/唯一可能的值是HEAP_NO_SERIALIZELPCVOID lpMem/指定的内存块)7、 撤销堆 HeapDestroyBOOL HeapDestroy(HANDLE hHeap);2.3.2堆的使用特点1、用来分配许多较小的数据块,可不考虑分配粒度和页面边界。在堆管理中,有堆管理器来替它管理,不需管理具体的事情

24、如页面边界和分配粒度等问题。堆成功创建以后, 整个堆的构造如图2所示, 堆是以堆管理结构开始的,图中的初始区域是参数 dwInitialSize指定的。暂时未用的保留区域(预备区域), 它和初始区域的总和由参数dwMaximumSize指定。 初始区域管理结构 预备区域 图2 堆的结构保留区域中的多数页面并没有提交到物理存储器。 随着从堆中越来越多地进行内存分配, 堆管理器逐渐把更多的物理存储器提交给堆。堆的物理存储器从系统页文件中分配, 在释放时有专门的堆管理器负责对已占用物理存储器的回收。 应用程序可以使用系统提供的一系列函数来创建自己的堆并对堆中的内存进行管理, 主要包括堆内存块的分配和

25、堆内存块的释放, 以及堆内存块的枚举、 计算内存块的大小等等。堆用来分配较小的数据块,也就是说,适合管理大量的小对象。比如,用来管理链表和二叉树。例如:使用堆,实现二叉排序数,实现动态分配内存在程序中使用两个堆,在二叉树的每个结点中,包含了左指针、右指针、一个键以及一个指向数据堆中的数据记录指针。定义如下:typedef struct _TREENODE struct _TREENODE *Left, *Right;/ 左指针、右指针TCHAR keyKEY_SIZE;/ 键LPTSTR pData;/ 指向数据堆中的数据记录指针 TREENODE, *LPTNODE, *LPPTNODE;其

26、中,键保存在结点堆(node heap)中,节点堆的定义如下:hNode=HeapCreate(HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE,NODE_HEAP_ISIZE, 0);数据堆(data heap)定义如下;hData=HeapCreate(HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE,DATA_HEAP_ISIZE, 0);为两个堆分配内存pNode = HeapAlloc (hNode, HEAP_ZERO_MEMORY, NODE_SIZE);pString = HeapAlloc (hData,

27、 HEAP_ZERO_MEMORY,(SIZE_T)(KEY_SIZE + _tcslen (dataHold) + 1) * TSIZE); 2、系统在进程的地址空间创建(默认)堆(1M),对默认堆的访问是顺序进行的。创建应用程序时可改变默认区域大小,不能撤销进程的默认堆。Widows 中,每个进程有一个缺省堆,这种堆是进程创建时,由系统创建的堆。默认时,该堆的大小是1MB,可以通过链接器开关/HEAP来修改缺省堆大小。系统在任一时刻只能有一个线程在缺省堆中分配或释放内存块。每一个堆都有它自己的句柄可以使用GetProcessHeap函数来获得缺省堆句柄。进程默认堆是供所有线程使用的,每当线

28、程需要从堆中分配释放内存区时,系统会同步堆,所以访问速度较慢。它的默认大小是1M,可以通过链接命令改变其大小例如:改变默认堆的大小#pragma comment(linker,/HEAP:102400000,1024000)/将堆改变为100M。第一个值是堆的保留空间,第二个值是堆开始时提交的物理内存大小。3、一个进程可以使用多个堆一个进程除了默认堆,还可以调用HeapCreate函数来创建额外的堆创建额外堆的好处:对数据保护。创建两个或多个独立的堆,每个堆保存不同的结构,对两个堆分别操作,可以使问题局部化;更有效的内存管理,创建额外的堆,管理同样大小的对象。这样在释放一个空间后可以刚好容纳另

29、一个对象。默认堆的访问是依次进行的。由于堆没有安全性属性堆函数必须执行额外的代码来保证线程安全性。通过创建额外的堆可以避免同步开销。快速释放。我们可以直接释放整个堆而不需要手动的释放每个内存块。这不但极其方便,而且还可以更快的运行例如:在上面的程序中,用堆实现二叉排序树,就创建了两个堆,一个是结点堆,用来保存数据结构,一个是数据堆,用来保存数据。3.总结通过一周多的时间,完成了本次的大作业,每天都是各种查资料,过程实在是太痛苦了,但是终究还是完成了,基本了解了本课程内存管理的几种方法,学到了许多东西的,自己也对windows程序设计也有了初步的认识,可是其中很多地方不懂,以后必须多多的练习!参

30、考文献1 (美)Johnson M.Hart. Windows System Programming中文版(原书第四版).北京:机械工业出版社 2010.102 裘宗燕 从问题到程序:程序设计与C语言引论(第二版).北京:机械工业出版社2011.053 (美)Richard Johnsonbaugh Martin Kalin 面向对象程序设计(第二版).北京:机械工业出版社 2002.094 (美) Jeffrey Richter windows核心编程(第五版).北京:清华大学出版社 2008.09致谢非常感谢老师平时的教导以及感谢老师提供的教学课件,本次大作业就是按照课件一一写出来的,然后感谢班上同学为我解答问题,以及网上提供资料的各位朋友!谢谢!

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 建筑/施工/环境 > 项目建议


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号