操作系统实验学生用讲义.doc_第1页
操作系统实验学生用讲义.doc_第2页
操作系统实验学生用讲义.doc_第3页
操作系统实验学生用讲义.doc_第4页
操作系统实验学生用讲义.doc_第5页
已阅读5页,还剩58页未读 继续免费阅读

下载本文档

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

文档简介

操作系统课程设计讲义(学生稿)编写人:朱敏、杜中军等2009年9月于成都.川大望江校区目 录第一部分 基于Windows环境的实验4实验一 读者写者问题41.1实验要求41.2 实验环境41.3测试数据文件格式41.4 试验分析51.5 相关API函数说明51.6简单说明:12实验二 内存管理142.1实验要求142.2实验目的142.3实验内容152.4实验环境152.5实验提示152.5.1源程序提示152.5.2相关API函数说明16第二部分 基于Linux环境的实验22实验一 shell 程序221.1 实验目的221.2 实验要求221.2.1 ysh解释程序的重要特征221.2.2 ysh解释程序的具体要求231.3相关基础知识261.3.1 shell与内核的关系261.3.2 系统调用271.4实验环境361.5程序的实现361.5.1数据结构361.5.2程序结构371.6实验总结45实验二:作业调度系统462.1实验内容462.2实验目的462.3环境要求462.4实验要求462.4.1实验包括的程序462.4.2调度策略482.5实验提示482.5.1重要数据结构482.5.2作业调度程序的实现492.5.3作业控制命令的实现52实验三 文件系统533.1实验内容533.2实验目的533.3环境要求533.4 实验要求533.5实验提示543.5.1数据结构543.5.2文件操作函数的实现55第一部分 基于Windows环境的实验实验一 读者写者问题1.1实验要求 创建一个控制台进程。此进程包含n个线程。用这n个线程来表示n个读者或写者。每个线程按相应测试数据文件(后面有介绍)的要求进行读写操作。用信号量机制分别实现读者优先和写者优先的读者-写者问题。 读者-写者问题的读写操作限制(包括读者优先和写者优先): 1)写-写互斥,即不能有两个写者同时进行写操作。 2)读-写互斥,即不能同时有一个线程在读,而另一个线程在写。 3)读-读允许,即可以有一个或多个读者在读。 读者优先的附加限制:如果一个读者申请进行读操作时已有另一个读者正在进行读操作,则该读者可直接开始读操作。 写者优先的附加限制:如果一个读者申请进行读操作时已有另一写者在等待访问共享资源,则该读者必须等到没有写者处于等待状态后才能开始读操作。运行结果显示要求:要求在每个线程创建、发出读写操作申请、开始读写操作和结束读写操作时分别显示一行提示信息,以确定所有处理都遵守相应的读写操作限制。1.2 实验环境windows 2000/xp ,visual c+1.3测试数据文件格式测试数据文件包括n行测试数据,分别描述创建的n个线程是读者还是写者,以及读写操作的开始时间和持续时间。每行测试数据包括四个字段,各个字段间用空格分隔。第一字段为一个正整数,表示线程序号。第二字段表示相应线程角色,R表示读者,w表示写者。第三字段为一个正数,表示读写操作的开始时间:线程创建后,延迟相应时间(单位为秒)后发出对共享资源的读写申请。第四字段为一个正数,表示读写操作的持续时间。当线程读写申请成功后,开始对共享资源的读写操作,该操作持续相应时间后结束,并释放共享资源。下面是一个测试数据文件的例子:1 R 3 52 W 4 53 R 5 24 R 6 55 W 5.1 3由于牵涉格式的问题,最好在记事本中手工逐个键入数据,而不要拷贝粘贴数据, 1.4 试验分析 可以将所有读者和所有写者分别存于一个读者等待队列和一个写者等待队列中,每当读允许时,就从读者队列中释放一个或多个读者线程进行读操作;每当写允许时,就从写者队列中释放一个写者进行写操作。1读者优先 读者优先指的是除非有写者在写文件,否则读者不需要等待。所以可以用一个整型变量read_count记录当前的读者数目,用于确定是否需要释放正在等待的写者线程(当read_count=0时,表明所有的读者读完,需要释放写者等待队列中的一个写者)。每一个读者开始读文件时,必须修改read_count变量。因此需要一个互斥对象mutex来实现对全局变量read_count修改时的互斥。 另外,为了实现写-写互斥,需要增加一个临界区对象write。当写者发出写请求时,必须申请临界区对象的所有权。通过这种方法,也可以实现读-写互斥,当read_count=1时(即第一个读者到来时),读者线程也必须申请临界区对象的所有权。当读者拥有临界区的所有权时,写者阻塞在临界区对象write上。当写者拥有临界区的所有权时,第一个读者判断完“read_count=1”后阻塞在write上,其余的读者由于等待对read_count的判断,阻塞在mutex上。2写者优先 写者优先与读者优先类似。不同之处在于一旦一个写者到来,它应该尽快对文件进行写操作,如果有一个写者在等待,则新到来的读者不允许进行读操作。为此应当添加一个整型变量write_count,用于记录正在等待的写者的数目,当write_count=0时,才可以释放等待的读者线程队列。 为了对全局变量write_count实现互斥,必须增加一个互斥对象mutex3。 为了实现写者优先,应当添加一个临界区对象read,当有写者在写文件或等待时,读者必须阻塞在read上。读者线程除了要对全局变量read_count实现操作上的互斥外,还必须有一个互斥对象对阻塞read这一过程实现互斥。这两个互斥对象分别命名为mutexl和mutex2。1.5 相关API函数说明1CreateThread函数功能:该函数创建一个在调用进程的地址空间中执行的线程。函数模型:HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlag,LPDWORD lpThreadId);参数l lpThreadAttributes:指向一个SCURITY_ATTRIBUTES结构,该结构决定了返回的句柄是否可被子进程继承。若1pThreadAttributes为NULL,则句柄不能被继承。 在windows NT中该结构的lpSecurityDescriptor成员定义了新进程的安全性描述符。若lpThreadAttributes为NULL,则线程获得一个默认的安全性描述符。l dwStackSize:定义原始堆栈提交时的大小(按字节计)。系统将该值舍入为最近的页。若该值为0,或小于默认时提交的大小,默认情况是使用与调用线程同样的大小。更多的信息,请看Thread Stack Size。l lpStartAddress:指向一个LPTHREAD_START_ROUTINE类型的应用定义的函数,该线程执行此函数。该指针还表示远程进程中线程的起始地址。该函数必须存在于远程进程中。l lpParameter:定义一个传递给该进程的32位值。l dwCreationFlags:定义控制进程创建的附加标志。若定义了CREATE_SUSPENDED标志,线程创建时处于挂起状态,并且直到ResumeThread函数调用时才能运行。若该值为0,则该线程在创建后立即执行。l lpThreadId:指向一个32位值,它接收该线程的标识符。返回值: 若函数调用成功,返回值为新线程的句柄;若函数调用失败,返回值为NULL。备注:新线程的句柄创建时设为THREAD_ALL_ACCESS访问权限。若未提供安全性描述符,则该句柄可被任何要求一个线程对象句柄的函数所使用。若提供了安全性描述符,则以后使用该句柄时,将在授权访问以前执行访问检查。若访问检查拒绝访问,则请求进程不能使用该句柄获得对该线程的访问。 线程从lpStartAddress参数定义的函数处开始执行。若该函数返回,系统将默认地认为以调用ExitThread函数的方法终止该线程。使用GetExitcodeThread函数来获得线程的返回值。 线程创建时拥有THREAD_PRIORITY_NORMAL优先权。使用GetThreadPriority和setThreadPriority函数可以获得和设置线程的优先权值。 一个线程终止时,该线程对象被设为发信号状态,以满足在该对象上等待的所有进程。 一个线程对象始终存在于系统中,直到该线程终止,且它所有的句柄都已通过调用CloseHandle函数关闭。2Exi tThread函数功能:该函数结束一个线程。函数原型:VOID ExitThread (DWORD dwExitCode); 参数:l dwExitCode:定义调用线程的退出代码。使用GetExitCodeThread函数来检测一个线程的退出代码。 返回值:无。 备注: , 调用ExitThread函数,是结束一个线程的较好的方法。调用该函数后(或者直接地调用,或者从一个线程过程返回),当前线程的堆栈取消分配,线程终止。若调用该函数时,该线程为进程的最后一个线程,则该线程的进程也被终止。 线程对象的状态变为发信号状态,以释放所有正在等待该线程终止的其他线程。线程的终止状态从STILL_ACTIVATE变为dwExitCode参数的值。 线程结束时不必从操作系统中移去该线程对象。当线程的最后一个句柄关闭时,该线程对象被删除。3S1eep 函数功能: 该函数对于指定的时间间隔挂起当前的执行线程。函数原型:VOID Sleep(DWORD dwMilliseconds);参数:dwMilliseconds:定义挂起执行线程的时间,以毫秒(ms)为单位。取值为0时,该线程将余下的时间片交给处于就绪状态的同一优先级的其他线程。若没有处于就绪状态的同一优先级的其他线程,则函数立即返回,该线程继续执行。若取值为INFINITE则造成无限延迟。返回值:该函数没有返回值。备注:一个线程可以在调用该函数时将睡眠时间设为0ms,以将剩余的时间片交出。4CreateMutex函数功能:该函数创建有名或者无名的互斥对象。函数原型:HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,BOOL bInitialOwner,LPCTSTR lpName);参数:l lpMutexAttributes:指向SECURITY_ATTRIBUTES结构的指针,该结构决定子进程是否能继承返回句柄。如果lpMutexAttributes为NULL,那么句柄不能被继承。 在Windows NT中该结构的lpSecurityDescriptor成员指定新互斥对象的安全描述符。如果lpMutexAttributes为NULL,那么互斥对象获得默认的安全描述符。l bInitialOwner:指定互斥对象的初始所属身份。如果该值为TRUE,并且调用者创建互斥对象,那么调用线程获得互斥对象所属身份。否则,调用线程不能获得互斥对象所属身份。判断调用者是否创建互斥对象请参阅返回值部分。l lpName:指向以NULL结尾的字符串,该字符串指定了互斥对象名。该名字的长度小于MAX_PATH且可以包含除反斜线()路径分隔符以外的任何字符。名字是区分大小写的。 如果lpName与已存在的有名互斥对象名相匹配,那么该函数要求用MUTEX_ALL_ ACCESS权限访问已存在的对象。在这种情况下,由于参数binitialOwner已被创建进程所设置,该参数被忽略。如果参数lpMutexAttributes不为NULL,它决定句柄是否解除继承,但是其安全描述符成员被忽略。 如果lpName为NULL,那么创建的互斥对象无名。 如果lpName与已存在的事件、信号量、可等待定时器、作业或者文件映射对象的名字相匹配,那么函数调用失败,并且GetLastError函数返回ERROR_INVALID_HANDLE,其原因是这些对象共享相同的名字空间。 返回值: 如果函数调用成功,返回值是互斥对象句柄;如果函数调用之前,有名互斥对象已存在,那么函数给已存在的对象返回一个句柄,并且函数GetLastError返回ERROR_ALREADY_EXISITS,否则,调用者创建互斥对象。 如果函数调用失败,则返回值为NULL。若想获得更多错误信息,请调用GetLastError函数。 备注: 由函数CreateMutex返回的句柄有MUTEX_ALL_ACCESS权限可以去访问新的互斥对象,并且可用在请求互斥对象句柄的任何函数中。 调用进程中的任何线程可以在调用等待函数时指定互斥对象句柄。当指定对象的状态为信号态时,返回单对象等待函数。当任何一个或者所有的互斥对象都为信号态时,返回多对象等待函数指令。等待函数返回后,等待的线程被释放,继续向下执行。 当一个互斥对象不被任何线程拥有时,处于信号态。创建该对象的线程可以使用bInitialOwner标志来请求立即获得对该互斥对象的所有权。否则,线程必须使用等待函数来请求所有权。当互斥对象处于信号态,等待的线程获得对该对象的所有权时,此互斥对象的状态被设置为非信号态,等待函数返回。任意时刻,仅有一个线程能拥有该互斥对象,线程可以使用ReleaseMutex函数来释放对这个互斥对象的所有权。 若线程已经拥有了一个互斥对象,那么它可以重复调用等待函数而不会发生阻塞,一般情况下,用户不会重复等待同一个互斥对象,这种机制防止了线程因等待它已经拥有的互斥对象而发生死锁。然而,线程必须为每一次等待调用一次ReleaseMutex函数来释放该互斥对象。 两个或多个进程可以调用CreateMutex来创建同名的互斥对象,第一个进程实际创建互斥对象,以后的进程打开已存在的互斥对象的句柄。这使得多个进程可以得到同一个互斥对象的句柄,从而减轻了用户的负担,使用户不必判断创建进程是否为第一个启动的进程。使用这种技术时,应该把blnitialOwner标志设为FALSE;否则很难确定开始时哪一个进程拥有该互斥对象。 由于多进程能够拥有相同互斥对象的句柄,通过使用这个对象,可使多进程同步。以下为共享对象机制:l 如果CreateMutex中的lpMutexAttributes参数允许继承,由CreateProcess函数创建的子进程可以继承父进程的互斥对象句柄。l 一个进程可以在调用DuplicateHandle函数时指定互斥对象句柄来创建一个可以被其他进程使用的双重句柄。一个进程在调用OpenMutex或CreateMutex函数时能指定互斥对象名。l 使用closeHandle函数关闭句柄,进程结束时系统自动关闭句柄。当最后一个句柄被关闭时, 互斥对象被销毁。5ReleaseMutex 函数功能: 该函数放弃指定互斥对象的所有权。 函数原型:Bool ReleaseMutex (HANDLE hMutex) 参数:l hMutex:互斥对象句柄。为CreateMutex或OpenMutex函数的返回值。 返回值: 如果函数调用成功,那么返回值是非零值;如果函数调用失败,那么返回值是零值。若想获得更多错误信息,请调用GetLastError函数。 备注: 如果调用线程不拥有互斥对象,ReleaseMutex函数失败。 一个线程通过调用等待函数拥有互斥对象。创建该互斥对象的线程也拥有互斥对象,而不需要调用等待函数。当互斥对象的所有者线程不再需要互斥对象时,它可以调用ReleaseMutex函数。 当一个线程拥有一个互斥对象后,它可以用该互斥对象多次调用等待函数而不会阻塞。这防止一个线程等待一个它已拥有的互斥对象时出现死锁。不过,为了释放所有权,该线程必须为每一个等待操作调用一次ReleaseMutex函数。6WaitForSingleObject 函数功能: 当下列情况之一发生时该函数返回:(1)指定对象处于信号态;(2)超时。 函数原型:DWORD WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds);参数: l hHandle:等待对象句柄。若想了解指定句柄的对象类型列表,参阅下面备注部分。 在wndowsNT中,句柄必须有SYNCHRONIZE访问权限。若想获得更多的信息,请查看Standard Access Rights。l dwMilliseconds:指定以毫秒为单位的超时间隔。如果超时,即使对象的状态是非信号态的并且没有完成,函数也返回。如果dwMilliseconds是0,函数测试对象的状态并立刻返回;如果dwMillseconds是INFINITE,函数从不超时。 返回值: 如果函数调用成功,返回值表明引起函数返回的事件。可能值如下:l WAIT_ABANDONED:指定对象是互斥对象,在线程被终止前,线程没有释放互斥对象。互斥对象的所属关系被授予调用线程,并且该互斥对象被置为非信号态。l WAIT_OBJECT_0:指定对象的状态被置为信号态。l WAIT_TIMEOUT:超时,并且对象的状态为非信号态。 如果函数调用失败,返回值是WAIT_FAILED。若想获得更多错误信息,请调用GetLastError函数。 备注: WaitForsingleObiects函数决定等待条件是否被满足。如果等待条件并没有被满足,调用线程进入一个高效的等待状态,当等待满足条件时占用非常少的处理器时间。 在运行前,一个等待函数修改同步对象类型的状态。修改仅发生在引起函数返回的对象身上。例如,信号的计数减l。 WaitForSingleObj ect函数能等待的对象包括:Change notification(改变通告);Console input(控制台输入);Event(事件);Job(作业);Mutex(互斥对象);Process(进程);Semaphore(信号量);Thread(线程);Waitable timer(可等待定时器)。 当使用等待函数或代码直接或间接创建窗口时,一定要小心。如果一个线程创建了任何窗口,它必须处理进程消息。消息广播被发送到系统的所有窗口。一个线程用没有超时的等待函数也许会引起系统死锁。间接创建窗口的两个例子是DDE和COM CoInitialize。因此,如果用户有一个创建窗口的线程,用MsgWaitForMultipleObjects或MsgWaitForMultipleObjectsEx函数,而不要用SignalObjectAndWait函数。7WaitForMultipleObjects 函数功能: WaiForMultipleObjects函数当下列条件之一满足时返回:(1)任意一个或全部指定对象处于信号态;(2)超时间隔已过。 函数原型:DWORD waitF0rMultipleObjects (DWORD nCount,CONST HANDLE *lpHandles, BOOL fWaitAll,IDWORD dwMilliSeconds);参数:l nCount: 指定由lpHandles所指向的数组中的句柄对象数目最大对象句柄数目MAXIMUM_WAIT OBJECTS。l 1p_Handles:指向对象句柄数组的指针。该数组可以包含不同类型对象的句柄。在windowsNT中,该句柄必须有SYNCHRONIZE访问权限。若想获得更多的信息,请查看Standard Access Rights。l fWaitAll:指定等待类型。如果为TRUE,当lpHandles指向的数组里的全部对象为信号态时,函数返回。如果为FALSE,当由lpHandles指向的数组里的任一对象为信号态时,函数返回。对于后者,返回值指出引起函数返回的对象。l dwMilliseconds:指定以毫秒为单位的超时间隔。如果超时,即使fwaitAll参数指定的条件没有满足,函数也返回。如果dwMilliseconds是0,函数测试指定对象的状态并立刻返回。 如果dwMilliseconds是INFINITE,函数从不超时。 返回值: 如果函数调用成功,返回值表明引起函数返回的事件。可能值如下:l WAIT_OBJECT_0到 WAIT_OBJECT_0+nCount-1:如果bwaitAll为TRUE,那么返回值表明所有指定对象的状态为信号态。如果bWaitA11为FALSE,那么返回值减去WAIT_OBJECT_0表明引起函数返回的对象的pHandles数组索引。如果多于一个对象变为信号态,则返回的是数组索引最小的信号态对象索引。l WAIT_ABANDONED_0到WAIT_ABANDONED_0+nCount-1:如果bWaitAll为TRUE,那么返回值表明所有指定对象的状态为信号态,并且至少一个对象是己放弃的互斥对象。如果bWaitAll为FALSE,那么返回值减去WAIT_ABANDONED_0表明引起函数返回的放弃互斥对象lpHandles数组索引。l WAIT_TIMEOUT:超时并且由参数bwaitAll指定的条件没有满足。 如果函数调用失败,返回值是WAITFAILED。若想获得更多错误信息,请调用GetLastError函数。8CreateSemapore 函数功能: 该函数是创建一个有名或者无名信号对象。 函数原型: HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpAttributes,LONG lInitia1Cout,LONG lMaximumCount,LPCTSTR lpName);l 1pAttributes:安全属性。如果是NULL就表示要使用默认属性l lInitialC0unt:Semaphore的初值。必须大于或等于0,并且小于或等于Maximumcount。l lMaximumcount:Semaphore的最大值。这也就是在同一时间内能够锁住semaphore之线程的最多个数。l lpName:Semaphore的名称(一个字符串)。任何线程(或进程)都可以根据这一名称引用到这个Semaphore。这个值可以是NULL,意思是产生一个没有名字的Semaphore。 返回值: 如果成功就传回一个handle,否则传NULL。不论哪一种情况,GetLastError都会传回一个合理的结果。如果指定的semaphore名称已经存在,则该函数还是成功的,GetLastError会传回ERROR_ALREADY_EXISTS。9ReleaseSemaphore 函数功能: 该函数将指定信号对象的计数增加一个指定的数量。 函数原型: BOOL ReleaseSemaphore(HANDLE hSemaphore,LONG 1ReleaseCount,LPLONG lpPreviousCount) 参数:l hSemaphore:Semaphore的handle。l lReleaseCount:Semaphore现值的增额。该值不可以是负值或0。l lpPreviousCount:借此返回Semaphore原来的值。 返回值: 如果成功,则返回TRUE。否则返回FALSE。失败时可调用GetLastError获得原因。 备注: 无论Releasesemaphore对于Semaphore所造成的当前值怎样增加,都绝对不会超过CreateSemaphore时所指定的lMaximumCount。 请记住,lpPreviousCount所传回来的是一个瞬间值。你不可以把lReleaseCount加上*lpPreviousCount,就当做是semaphore的当前值,因为其他线程可能已经改变TSemaphore的值。 与mutex不同的是,调用ReleaseSemaphore的那个线程,并不一定就是调用waitxxx的那个线程。任何线程都可以在任何时间调用Releasesemaphore,解除被任何线程锁定的semaphore。10InitializeCriticalSection 函数功能: 该函数初始化临界区对象。 函数原型: VOID InltlallzeCriticalSection(LPCRITICAL_SECTION IpCritiCalSection); 参数:l lpCriticalSection:指向临界区对象的指针。 备注: 单进程的所有线程可以使用互斥同步机制的临界区对象。但是,不能保证线程获得临界区所有权的顺序,系统将对所有线程公平处理。 进程负责分配临界区对象使用的存储空间,这可以通过声明CRITICAL_SECTION类型的变量来完成。在使用临界区之前,该进程的一些线程必须使用InitializeCriticalSection或InitializeCriticalSectionAndSpinCount函数来初始化该临界区对象。11EnterCriticalSection函数功能:该函数是等待指定临界区对象的所有权。当调用线程被赋予所有权时,该函数返回。函数原型:VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);参数:l lpCriticalSection:指向临界区对象的指针。12LeaveCriticalSection函数功能:该函数释放指定临界区对象的所有权。函数原型:VOID LeaveCriticalSectiOil(LPCRITICAL_SECTION lpCriticalSection);参数:l lpCriticalSection:指向临界区对象的指针。1.6简单说明:在Win32 API中,互斥对象Mutex与P,V中的互斥信号量有类似的地方,但也有不同:在P,V操作中的互斥信号量可以有一个任意大小的初值,但互斥对象Mutex没有,它可以被看成是初值为1的互斥信号量。而且一个线程在取得Mutex的所有权之后,即使不调用ReleaseMutex函数,在线程结束时,线程也会自动释放Mutex的所有权。临界区对象CriticalSection则与P、V操作中初值为1的互斥信号量语意相同。它在线程结束时,会将CriticalSection的所有权传递给它的同类型线程。这样就可以满足在一个线程中申请所有权,在另一个线程释放所有权的要求。在读者优先中的write互斥信号量以及写者优先中的read和write互斥信号量就应该用CriticalSection实现而不应该用Mutex。用WaitForSingleSignal函数可以获得一个Mutex的所有权,类似于P操作,而ReleaseMutex函数可以释放一个Mutex的所有权,类似于V操作。用E nterCri tical Section函数可以进入一个Cri ticalSection,类似于P操作,而LeaveCriticalSection函数离开一个CriticalSection,类似于V操作。备注:ReaderPriority和WriterPriority函数最后都有 wait_for_ all=WaitForMultipleObjects(n_thread,h_Thread,TRUE,-1);是因为主函数要等待所有的线程都结束之后才退出。因为不知道有多少线程,所以源文件最初有: #define MAX_THREAD_NUM 64 /最大线程数目即线程最多不能超过MAX_THREAD_NUM个。线程对象的数组大小为MAX_THREAD_NUM。如果创建的线程没有这么多,空间会有浪费,但是可以达到牺牲空间来节省时间的目的。有的书上还有其他的处理方法。一种是在主函数的最后加上Sleep(1000),即通过主函数睡眠的方法等待其他线程结束,这当然不是一种很好的方法,因为睡眠等待的时间没法控制。另一种方法是增加循环变量threadCount(线程的个数),每个线程结束的时候就会执行语句ThreadCount-;主函数的最后测试:while(threadCount0);但是这种方式会让主函数循环等待,浪费了CPU资源。相比之下,考虑到运行效率,还是实例中给出的方法比较好些。实验二 内存管理2.1实验要求 使用Windows 2000XP的API函数,编写一个包含两个线程的进程,一个线程用于模拟内存分配活动,一个线程用于跟踪第一个线程的内存行为,而且要求两个线程之间通过信号量实现同步。模拟内存活动的线程可以从一个文件中读出要进行的内存操作,每个内存操作包括如下内容: 时间:操作等待时间。 块数:分配内存的粒度。操作:包括保留(reserve)一个区域、提交(commit)一个区域、释放(release)一个区域、回收(decommit)一个区域和加锁(10ck)与解锁(unlock)一个区域,可以将这些操作编号存放于文件。 保留是指保留进程的虚拟地址空间,而不分配物理存储空间。 提交在内存中分配物理存储空间。 回收是指释放物理内存空间,但在虚拟地址空问仍然保留,它与提交相对应,即可以回收已经提交的内存块。 释放是指将物理存储和虚拟地址空间全部释放,它与保留(reserve)相对应,即可以释放已经保留的内存块。大小:块的大小。访问权限:共五种,分别为PAGE_READONLY,PAGE_READWRITE,PAGE_EXECUTE,PAGE_EXECUTE_READ和PAGE_EXETUTE_READWRITE。可以将这些权限编号存放于文件中跟踪线程将页面大小、已使用的地址范围、物理内存总量,以及虚拟内存总量等信息显示出来。2.2实验目的 本实习的目的是从不同侧面了解windows 2000XP对用户进程的虚拟内存空间的管理、分配方法。同时需要了解跟踪程序的编写方法(与被跟踪程序保持同步,使用Windows提供的信号量)。对Windows分配虚拟内存、改变内存状态,以及对物理内存(physical memory)和页面文件(page file)状态查询的API函数的功能、参数限制、使用规则要进一步了解。 默认情况下,32位Windows 2000XP上每个用户进程可以占有2GB的私有地址空间,操作系统占有剩下的2GB。Windows 2000XP在X86体系结构上利用二级页表结构来实现虚拟地址向物理地址的变换。一个32位虚拟地址被解释为三个独立的分量页目录索引、页表索引和字节索引它们用于找出描述页面映射结构的索引。页面大小及页表项的宽度决定了页目录和页表索引的宽度。Windows进程的虚拟地址空间中也有三种状态的页面:空闲页面、保留页面和提交页面。空闲(Free)页面:空闲页面是指那些可以保留或提交的可用页面。 保留(ReserVed)页面:保留页面是逻辑页面已分配但没有分配物理存储的页面。设置这种状态的效果是可以保留一部分虚拟地址,这样,如果不预先释放这些地址,就不能被其他应用程序(如Malloc,LocalAlloc等)的操作所使用。 试图读或写空闲页面或保留页面将导致页面出错异常。保留页面可被释放或提交。提交(Committed)页面:提交页面是物理存储(在内存中或磁盘上)已被分配的页面。可对它加以保护,不许访问或允许只读访问,或允许读写访问。提交也可以被回收以释放存储空间,从而变成保留页面。2.3实验内容使用Windows 2000XP的API函数,编写一个包含两个线程的进程,一个线程用于模拟内存分配活动,一个线程用于跟踪第一个线程的内存行为,而且要求两个线程之间通过信号量实现同步。模拟内存活动的线程可以从一个文件中读出要进行的内存操作。内存操作包括保留(reserve)一个区域、提交(commit)一个区域、释放(release)一个区域、回收(decommit)一个区域和加锁(10ck)与解锁(unlock)一个区域,可以将这些操作编号存放于文件。2.4实验环境Windows2000/XP2.5实验提示2.5.1源程序提示1Makefile.cpp 本程序主要实现将操作写入文件,采用了c语言的fwrite函数直接以结构(struct)为单位写入文件。用了两层循环,外层循环控制对内存的操作(保留、提交、锁、解锁、回收、释放),内层循环控制对内存操作的权限(PAGE_READONLY、PAGE_READWRITE、PAGE_EXECUTE、PAGE_EXECUTE_READ、PAGE_EXECUTE_READWRITE)用随机数生成等待执行的时间和分配的粒度。2Memory-op.cpp (1)主函数 创建两个线程,并将返回的句柄存人数组中。 创建两个信号量(allo,trac)分别用于通知跟踪线程和记录线程。 用函数WaitForMultipleObjects来等待两个线程的结束。 (2)Tracker线程(记录内存的状况) a)打开文件,准备输出。 b)等待线程Allocator的一次内存操作完毕(即等待信号量trac的释放)。 c)用函数GetSystemlnfo得到系统信息(该信息不随内存分配的变化而变化)。 d)用函数GlobalMemoryStatus得到内存信息(随内存的分配各项信息会有所改变)。用函数VirtualQuery得到虚拟内存基本信息(该信息不随内存分配的变化而变化)。 e)释放信号量,通知Allocator线程可以进行下一次内存分配活动。 f)如果已经记录了所有的内存分配信息,线程退出,否则转到b)。 (3)Allocator线程(模拟内存分配活动) a)打开文件(makefile.cpp的输出结果),准备读入。 b)等待Tracker输出的结束(即等待信号量allo的释放)。 c)读文件(makefile.cpp的输出结果)。 d)根据文件内容(protectlon)确定对内存操作时的权限。 e)根据文件内容(oper)确定对内存的具体操作。 f)释放信号量(trac)通知Tracker线程可以进行一次输出。 g)如果文件中所有的分配信息已经完成,线程退出,否则转到b)。2.5.2相关API函数说明1GetSystemInfo函数功能:该函数返回当前系统的信息。函数原型:VOID GetSystemInfo (LPSYSTEM_INFO lpSystemInfo);参数:lpSystemInfo: 指向SYSTEM_INFO结构的指针,SYSTEM_INFO结构由这个函数填充。 SYSTEMINFO结构定义如下:typedef struct_SYSTEM_INFO DWORD dwOemld; DWORD dwPageSize; LPVOID lpMinimumApplicationAddress; LPVOID lpMaximumApplicatlonAddress; DWORD dwActiveProcessorMask; DWORD dwNumberOfProcessors; DWORD dwProcessorType; DWORD dwAllocationGranularity; DWORD dwReserved; SYSTEM_INFO, *LPSYSTEM_INFO;返回值:该函数没有返回值,SYSTEM_INFO结构由这个函数填充。头文件:winbase.h。2GlobalMemoryStatus函数功能:该函数可以获得计算机系统中当前使用的物理内存和虚拟内存的信息。函数原型:VOID GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer)j参数:lpBuffer:指向MEMORYSTATUS数据结构。GlobalMemoryStatus函数将内存的当前信息存储在该结构中。 MEMORYSTATUS结构定义如下: typedef struct_MEMORYSTATUS DWORD dwLength; DWORD dwMemoryLoad; DWORD dwTotalPhys; DWORD dwAvailPhys; DWORD dwTotalPageFile; DWORD dwAvailPageFile; DWORD dwTotalVirtual; DWORD dwAvailVirtual; MEMORYSTATUS,* LPMEMORYSTATUS;返回值:无。备注:可以使用GlobalMemoryStatus函数判定你的应用程序能够分配多少与其他应用不冲突的内存。GIobalMemoryStatus函数返回的信息是不稳定的,不能保证两次调用该函数返回相同的信息结果。头文件:winbase.h。3VirtualAlloc 函数功能: 该函数可以在调用进程的虚拟地址中保留或提交页面。除非设置了MEMRESET标志,否则被这个函数分配的内存单元被自动初始化为0。 函数原型:LPVOID VirtualAlloc(LPVOID lpAddress,DWORD dwSize,DWORD flAllocationType,DWORDflProtect );参数:lpAddress:待分配空间的起始地址。如果指定的内存被保留,指定的地址将四舍五入到下一个64K边界。如果指定的内存已经被保留并且被提交,该地址将四舍五入到下一个页面边界。为了判断计算机中的页面大小,可以通过调用GetSystemInfo函数获得。如果该参数为NuLL,将由系统决定分配区域的地址。dwSize:定义分配空间的大小(以字节为单位)。如果参数lpAddress为NuLL,dwSize的值将四舍五人到下一个页面边界。否则,函数将分配包括从lpAddress到lpAddress+dwSize范围内的所有页面。这意味着,当一个2字节区域跨过一个页面边界时,将分配两个页面。ftAllocationType:定义分配类型,可以使用以下标志的任何组合定义分配类型:MEM_COMMIT: 在内存或磁盘页面文件中分配物理存储空间。提交一个已经分配的页面将不会导致函数失败。这意味着被提交的或没有被提交的页面都可以再被提交,而不用担心会出错。MEM_RESERVE:保留进程的虚拟地址空间,而不分配物理空间。备用的空间在没有被释放以前,不能被其他分配操作使用,如Malloc和LocalAlloc函数等等。备用页面可以被随后使用的VirtualAlloc函数提交。flProtect:指定存取保护位的类型。如果页面已经被提交,则指定下面任何一个属性时应该随同PAGE_GUARD(页保护)和PAG_NOCACHE(页无缓存)这两个属性(关于PAGE_GUARD和PAGE_NOCACHE的详细介绍可以参见MSDN)。PAGE_READONLY:使被提交的页面可读。试图在该页面中执行写操作将是违法的。如果系统区分只读和执行,在提交的页面中执行代码,将产生违法操作。PAGE_READWRITE:使被提交的页面可读写。PAGE_EXECUTE:使被提交的页面可执行,试图在该页面中执行读写都是违法的。PAGE_EXCUTE_READ:使被提交的页面可执行和可读。试图在该页面中执行写操作将是违法的。PAGE_EXCUTE_READWRITE:使被提交的页面可执行和可读写。PAGE_GUARD:保护标志,可以建立保护页面,任何对于该页面的存取会导致系统产生一个STATUS_GUARD_PAGE例外,并且关闭掉保护页面的属性,所以保护页面的行为像一个一次性存取警报器。返回值:如果函数成功,返回值为所分配的页面的基址;如果函数失败,返回值为NULL。若想获得更多错误信息,请调用GetLastError函数。 备注: VirtualAlloc函数执行如下操作: 提交一个前一个VirtuaAlloc函数保留的页面。 保留自由页面。 保留并提交自由页面。 你可以先使用VirtualAlloc函数保留一

温馨提示

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

评论

0/150

提交评论