操作系统实验教案打印版.docx
- 文档编号:17154861
- 上传时间:2023-07-22
- 格式:DOCX
- 页数:69
- 大小:2.08MB
操作系统实验教案打印版.docx
《操作系统实验教案打印版.docx》由会员分享,可在线阅读,更多相关《操作系统实验教案打印版.docx(69页珍藏版)》请在冰点文库上搜索。
操作系统实验教案打印版
《操作系统原理》
实验教案
(基于Windows2000/XP平台)
讲授人:
谢士春
安排授课时间:
2011-2012
(一)
授课对象:
09计算机科学与技术
实验项目列表
实验一多线程的创建与撤销
实验二线程的同步
实验三线程的互斥
实验四生产者-消费者问题
实验五进程通信
实验六动态链接库的建立和调试
实验七页面置换算法模拟
实验八文件的三种传输模式及性能比较
实验九磁盘的读写
附录部分(可扩充)
附录1读者-写者问题
附录2梨子苹果之PV操作
附录3命名管道编程规范
附录4DLL编程规范
实验一线程的创建与撤销
一、实验目的
通过本实验熟悉Windows系统提供的线程创建与撤销等API系统调用,掌握Windows系统环境下线程的创建与撤销方法。
二、实验内容
1.熟悉开发环境VisualC++6.0;
2.Windows系统环境下线程的创建与撤销方法;
3.编程:
在主线程中调用CreateThread()创建1个子线程,并在子线程中显示类似“Threadisrunning!
”等字样。
三、实验准备知识
相关的API函数的函数原型:
1.线程创建函数HANDLECreateThread();
HANDLECreateThread(
LPSECURITY_ATTRIBUTESlpThreadAttributes,//pointertosecurityattributes
DWORDdwStackSize,//initialthreadstacksize
LPTHREAD_START_ROUTINElpStartAddress,//pointertothreadfunction
LPVOIDlpParameter,//argumentfornewthread
DWORDdwCreationFlags,//creationflags
LPDWORDlpThreadId//pointertoreceivethreadID
);
线程函数原型DWORDWINAPIThread1Proc(LPVOIDlpParameter)
2.线程撤销函数
VOIDExitThread(
DWORDdwExitCode//exitcodeforthisthread
);
功能:
撤销一个线程。
该函数将终止线程的运行,并导致操作系统清除该线程使用的所有操作系统资源。
但是,C++资源(如C++类对象)将不被撤消。
说明:
如果在主线程函数(main函数)中调用ExitThread,那么应用程序的主线程将停止运行。
但是,如果进程中至少有一个线程还在运行,该进程将不会终止运行。
3.线程终止函数TerminateThread();
4.线程挂起函数Sleep();进程主动放弃剩余的时间片。
5.关闭句柄函数CloseHandle()。
说明:
关闭一个对象句柄,只是将相应对象的引用数减一,并不意味着终结该对象,除非引用数减至零。
四、程序源代码及注释
【主要源代码参考】
#include
#include
staticHANDLEhThread1=NULL;//存放创建的子进程的句柄
DWORDdwThreadID1;//存放创建的子进程的ID
DWORDWINAPIThread1Proc(LPVOID);//子线程函数的声明
intmain()//主线程
{//创建子线程
hThread1=CreateThread(NULL,0,Thread1Proc,
NULL,0,&dwThreadID1);
Sleep(5000);
CloseHandle(hThread1);//关闭句柄
ExitThread(0);//撤销本线程
return0;
}
//子线程的实现
DWORDWINAPIThread1Proc(LPVOIDlpParameter)
{
cout<<"Threadisrunning!
"< return0; } 五、实验结果输出 排版说明(小三、小四、五号) 实验二线程的同步 一、实验任务 该实验完成Windows中多线程同步运行的验证。 首先在主线程中创建一个子线程,成功创建后进入阻塞状态,直到子线程运行完毕后唤醒主线程。 二、实验目的 1.进一步掌握Windows系统环境下线程的创建与撤消。 2.熟悉Windows系统提供的线程同步API。 3.使用Windows系统提供的线程同步API解决实际问题。 三、实验准备知识 1.Wait函数 等待函数可使线程自愿进入等待状态,直到一个特定的内核对象变为受信(signaled)状态或超时为止。 函数原型: DWORDWaitForSingleObject( HANDLEhHandle,//handletoobjecttowaitfor DWORDdwMilliseconds//time-outintervalinmilliseconds ); 功能: 在指定的时间内等待一个对象。 举例: WaitForSingleObject(hThread,1000);//等待一个线程终止,等待1000毫秒 WaitForSingleObject(hMutex,INFINITE);//无限等待一个互斥对象, //直到变成“可信” DWORDWaitForMultipleObjects( DWORDnCount,//numberofhandlesinthehandlearray CONSTHANDLE*lpHandles,//pointertotheobject-handlearray BOOLfWaitAll,//waitflag DWORDdwMilliseconds//time-outintervalinmilliseconds ); 功能: 在指定时间内等待多个对象。 举例: HANDLEh[3]; h[0]=hThread1; h[1]=hThread2; h[2]=hThread3; DWORDdw=WaitForMultipleObject(3,h,true,-1); 2.信号量对象(Semaphore) 信号量对象用于对资源进行计数,它的使用规则如下: •如果当前资源的数量大于0,则处于“受信”状态。 •如果当前资源数量是0,则“未受信”状态。 所有等待此信号量的线程均进入等待状态(或称不可调度状态)。 函数原型: HANDLECreateSemaphore( LPSECURITY_ATTRIBUTESlpSemaphoreAttributes, //pointertosecurityattributes LONGlInitialCount,//initialcount LONGlMaximumCount,//maximumcount LPCTSTRlpName//pointertosemaphore-objectname ); 功能: 创建一个信号量。 举例: hHandle1=CreateSemaphore(NULL,0,5,”Semaphore1”); HANDLEOpenSemaphore( DWORDdwDesiredAccess,//accessflag BOOLbInheritHandle,//inheritflag LPCTSTRlpName//pointertosemaphore-objectname ); 功能: 打开一个已存在的信号量。 举例: hHandle2=OpenSemaphore(SEMAPHORE_MODIFY_STATE|SYNCHRONIZE,NULL,"SemaphoreName1"); BOOLReleaseSemaphore( HANDLEhSemaphore,//handletothesemaphoreobject LONGlReleaseCount,//amounttoaddtocurrentcount LPLONGlpPreviousCount//addressofpreviouscount ); 功能: 对指定的信号量对象增值。 举例: rc=ReleaseSemaphore(hHandle1,1,NULL); 四、程序源代码及注释 【主要源代码参考】 //定义全局变量,诸线程均可访问 staticHANDLEhThread1;//子进程的句柄,作为主线程的局部变量也行 staticHANDLEhHandle1=NULL;//信号量的句柄,全局变量 voidfunc();//子线程的声明 int_tmain(intargc,TCHAR*argv[],TCHAR*envp[]) { intnRetCode=0; DWORDdwThreadID1; DWORDdRes,err; hHandle1=CreateSemaphore(NULL,0,1,"SemaphoreName1");//创建一个信号量 if(hHandle1==NULL)printf("SemaphoreCreateFail! \n"); elseprintf("SemaphoreCreateSuccess! \n"); hHandle1=OpenSemaphore(SYNCHRONIZE|SEMAPHORE_MODIFY_STATE,NULL,"SemaphoreName1"); if(hHandle1==NULL)printf("SemaphoreOpenFail! \n"); elseprintf("SemaphoreOpenSuccess! \n"); hThread1=CreateThread((LPSECURITY_ATTRIBUTES)NULL,0, (LPTHREAD_START_ROUTINE)func, (LPVOID)NULL, 0,&dwThreadID1);//创建子线程 if(hThread1==NULL)printf("Thread1createFail! \n"); elseprintf("Thread1createSuccess! \n"); dRes=WaitForSingleObject(hHandle1,INFINITE);//主线程等待子线程结束 err=GetLastError(); printf("WaitForSingleObjecterr=%d\n",err); if(dRes==WAIT_TIMEOUT) printf("TIMEOUT! dRes=%d\n",dRes); elseif(dRes==WAIT_OBJECT_0) printf("WAIT_OBJECT! dRes=%d\n",dRes); elseif(dRes==WAIT_ABANDONED) printf("WAIT_ABANDONED! dRes=%d\n",dRes); elseprintf("dRes=%d\n",dRes); CloseHandle(hThread1); CloseHandle(hHandle1); ExitThread(0); returnnRetCode; } //实现子线程 voidfunc() { BOOLrc; DWORDerr; printf("NowInThread! \n"); rc=ReleaseSemaphore(hHandle1,1,NULL);//子线程唤醒主线程 err=GetLastError(); printf("ReleaseSemaphoreerr=%d\n",err); if(rc==0)printf("SemaphoreReleaseFail! \n"); elseprintf("SemaphoreReleaseSuccess! rc=%d\n",rc); } 五、实验结果输出 实验三线程的互斥 一、实验任务 完成两个子线程之间的互斥。 在主线程中使用系统调用CreateThread()创建两个子线程,并使两个子线程互斥的使用全局变量count。 二、实验目的 1.熟练掌握Windows系统环境下线程的创建与撤销。 2.熟悉Windows系统提供的线程互斥API。 3.使用Windows系统提供的线程互斥API解决实际问题。 三、实验准备知识 1.使用临界区对象(Criticalsection) CriticalSectionObject,Asegmentofcodethatisnotreentrantandthereforedoesnotsupportconcurrentaccessbymultiplethreads.Often,acriticalsectionobjectisusedtoprotectsharedresources。 通过定义在数据段中的一个CRITICAL_SECTION结构实现。 CRITICAL_SECTIONmyCritical; 并且在任何线程使用此临界区对象之前必须对它进行初始化。 voidInitializeCriticalSection(LPCRITICAL_SECTIONlpCriticalSection); 之后,任何线程访问临界区中数据的时候,必须首先调用EnterCriticalSection函数,申请进入临界区(又叫关键代码段,使用共享资源的任何代码都必须封装在此)。 在同一时间内,Windows只允许一个线程进入临界区。 所以在申请的时候,如果有另一个线程在临界区的话,EnterCriticalSection函数会一直等待下去,直到其他线程离开临界区才返回。 EnterCriticalSection函数用法如下: voidEnterCriticalSection(LPCRITICAL_SECTIONlpCriticalSection); 当操作完成的时候,还要将临界区交还给Windows,以便其他线程可以申请使用。 这个工作由LeaveCriticalSection函数来完成。 voidLeaveCriticalSection(LPCRITICAL_SECTIONlpCriticalSection); 当程序不再使用临界区对象的时候,必须使用DeleteCriticalSection函数将它删除。 voidDeleteCriticalSection(LPCRITICAL_SECTIONlpCriticalSection); 2.使用互斥锁(Interlocked) 提供一种手段来保证值的递增(减)能够以原子操作方式来进行,也就是不中断地进行。 LONGInterlockedIncrement(LPLONGlpAddend);//增一操作 LONGInterlockedDecrement(LPLONGlpAddend);//减一操作 LONGInterlockedExchangeAdd( PLONGAddend,//pointertotheaddend LONGIncrement//incrementvalue );//增减任意值 四、程序源代码及注释 【主要源代码参考】这里以使用临界区对象为例 staticintcount=5;//共享变量 staticHANDLEh1,h2;//两个子进程的句柄变量 LPCRITICAL_SECTIONhCriticalSection;//定义指向临界区对象的地址指针 CRITICAL_SECTIONCritical;//定义临界区 voidfunc1()//线程函数的定义不符合WIN32格式,后面CreateThread函数中 voidfunc2()//要附加强制类型转换 //主线程的实现 int_tmain(intargc,TCHAR*argv[],TCHAR*envp[]) { intnRetCode=0; DWORDdwThreadID1,dwThreadID2; hCriticalSection=&Critical;//将指向临界区的对象的指针指向临界区 InitializeCriticalSection(hCriticalSection);//初始化临界区 //创建子线程func1 h1=CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0, (LPTHREAD_START_ROUTINE)func1, (LPVOID)NULL, 0,&dwThreadID1); if(h1==NULL)printf("Thread1createFail! \n"); elseprintf("Thread1createsuccess! \n"); //创建子线程func2 h2=CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0, (LPTHREAD_START_ROUTINE)func2, (LPVOID)NULL, 0,&dwThreadID2); if(h2==NULL)printf("Thread2createFail! \n"); elseprintf("Thread2createsuccess! \n"); Sleep(1000); CloseHandle(h1); CloseHandle(h2); DeleteCriticalSection(hCriticalSection);//删除临界区 ExitThread(0); returnnRetCode; }//主线程结束 //子线程func2的实现 voidfunc2() { intr2; EnterCriticalSection(hCriticalSection);//进入临界区 r2=count; Sleep(100); r2=r2+1; count=r2; printf("countinfunc2=%d\n",count); LeaveCriticalSection(hCriticalSection);//退出临界区 } //子线程func1的实现 voidfunc1() { intr1; EnterCriticalSection(hCriticalSection);//进入临界区 r1=count; Sleep(500); r1=r1+1; count=r1; printf("countinfunc1=%d\n",count); LeaveCriticalSection(hCriticalSection);//退出临界区 } 五、实验结果输出参考 实验四生产者消费者问题 一、实验任务 1.在WINDOWS2000环境下,创建一个控制台进程,此进程包括多个生产者线程和多个消费者线程。 2.用信号量机制解决进程(线程)的同步与互斥问题。 二、实验目的 1.掌握基本的同步互斥算法,理解生产者和消费者模型。 2.了解Windows2000/XP中多线程的并发执行机制,线程间的同步和互斥。 3.学习使用Windows2000/XP中基本的同步对象,掌握相应的API函数。 三、实验要求 1.生产者消费者对缓冲区进行互斥操作。 2.缓冲区大小为10,缓冲区满则不允许生产者生产数据,缓冲区空则不允许消费者消费数据。 3.生产者消费者循环操作可随时终止。 四、实验准备知识 1.互斥量对象(mutex) 互斥对象能够确保线程拥有对单个资源的互斥访问权。 互斥对象包含一个引用数量,一个线程ID和一个递归计数器。 互斥对象的使用规则如下: •如果线程ID是0(这是个无效ID),互斥对象不被任何线程所拥有,互斥对象处于“受信”状态。 •如果ID是个非0数字,那么一个线程就拥有互斥对象,互斥对象处于“未受信”状态。 函数原型 HANDLECreateMutex( LPSECURITY_ATTRIBUTESlpMutexAttributes, //pointertosecurityattributes BOOLbInitialOwner,//flagforinitialownership LPCTSTRlpName//pointertomutex-objectname ); 作用: 创建一个命名或无名互斥对象。 举例: hHandle=CreateMutex(NULL,false,NULL); //创建一个无名互斥对象,放弃拥有权(ownership),此时互斥量处于“受信”状态。 HANDLEOpenMutex( DWORDdwDesiredAccess,//accessflag BOOLbInheritHandle,//inheritflag LPCTSTRlpName//pointertomutex-objectname ); 作用: 打开一个命名的互斥对象。 BOOLReleaseMutex( HANDLEhMutex//handletomutexobject ); 作用: 释放一个互斥对象,该函数同时将对象的递归计数器递减1。 当递归计数器到达0时,该线程ID也被置为0,同时该对象变为“受信”状态。 说明: 不同于其他内核对象,互斥对象有一个“线程所有权”的概念。 当一个线程调用ReleaseMutex函数释放互斥对象时,该函数要查看调用线程的ID是否与互斥对象中的线程ID相匹配。 如果两个ID相匹配,递归计数器就会递减;如果两个线程的ID不匹配,那么ReleaseMutex函数将不进行任何操作,而是将FALSE(表示失败)返回给调用者。 2.事件对象 事件对象能够通知一个操作已经完成。 在所有的内核对象中,事件内核对象是个最基本的对象。 它们包含一个使用计数,一个用于指明该事件是个自动重置的事件还是一个人工重置的事件的布尔值,另一个用于指明该事件处于“受信”状态还是“未受信”状态的布尔值。 函数原型 HANDLECreateEvent( LPSECURITY_ATTRIBUTESlpEventAttributes, //pointertosecurityattributes BOOLbManualReset,//flagforman
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 操作系统 实验 教案 打印