操作系統(tǒng)課程設計_第1頁
操作系統(tǒng)課程設計_第2頁
操作系統(tǒng)課程設計_第3頁
操作系統(tǒng)課程設計_第4頁
操作系統(tǒng)課程設計_第5頁
已閱讀5頁,還剩10頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

操作系統(tǒng)課程設一讀者寫者問題一、 實習要求在windows2000環(huán)境下,創(chuàng)建一個控制臺進程,此進程包含n個線程。用這n個線程來表示n個讀者或寫者。每個線程按相應測試數(shù)據(jù)文件(后面有介紹)的要求進行讀寫操作。用信號量機制分別實現(xiàn)讀者優(yōu)先和寫者優(yōu)先的讀者一寫者問題。讀者一寫者問題的讀寫操作限制(包括讀者優(yōu)先和寫者優(yōu)先):1) 寫一寫互斥,即不能有兩個寫者同時進行寫操作。2) 讀一寫互斥,即不能同時有一個線程在讀,而另一個線程在寫。3) 讀一讀允許,即可以有一個或多個讀者在讀。讀者優(yōu)先的附加限制:如果一個讀者申請進行讀操作時已有另一個讀者正在進行讀操作,則該讀者可直接開始讀操作。寫者優(yōu)先的附加限制:如果一個讀者申請進行讀操作時已有另一寫者在等待訪問共享資源,則該讀者必須等到沒有寫者處于等待狀態(tài)后才能開始讀操作。運行結果顯示要求:要求在每個線程創(chuàng)建、發(fā)出讀寫操作申請、開始讀寫操作和結束讀寫操作時分別顯示一行提示信息,以確定所有處理都遵守相應的讀寫操作限制。二、 測試數(shù)據(jù)文件格式測試數(shù)據(jù)文件包括n行測試數(shù)據(jù),分別描述創(chuàng)建的n個線程是讀者還是寫者,以及讀寫操作的開始時間和持續(xù)時間。每行測試數(shù)據(jù)包括四個字段,各個字段間用空格分隔。第一字段為一個正整數(shù),表示線程序號。第二字段表示相應線程角色,R表示讀者,W表示寫者。第三字段為一個正數(shù),表示讀寫操作的開始時間:線程創(chuàng)建后,延遲相應時間(單位為秒)后發(fā)出對共享資源的讀寫申請。第四字段為一個正數(shù),表示讀寫操作的持續(xù)時間。當線程讀寫申請成功后,開始對共享資源的讀寫操作,該操作持續(xù)相應時間后結束,并釋放共享資源。下面是一個測試數(shù)據(jù)文件的例子:TOC\o"1-5"\h\zR35W45R52R65W5.13注意在創(chuàng)建數(shù)據(jù)文件時,由于涉及到文件格式問題,最好在記事本中手工逐個鍵入數(shù)據(jù),而不要拷貝粘貼數(shù)據(jù),否則,本示例程序運行時可能會出現(xiàn)不可預知的錯誤。三、 實習分析可以將所有讀者和所有寫者分別存于一個讀者等待隊列和一個寫者等待隊列中,每當讀允許時,就從讀者隊列中釋放一個或多個讀者線程進行讀操作;每當寫允許時,就從寫者隊列中釋放一個寫者進行寫操作。讀者優(yōu)先讀者優(yōu)先指的是除非有寫者在寫文件,否則讀者不需要等待。所以可以用一個整型變量readcount記錄當前的讀者數(shù)目,用于確定是否需要釋放正在等待的寫者線程(當readcount=0時,表明所有的讀者讀完,需要釋放寫者等待隊列中的一個寫者)。每一個讀者開始讀文件時,必須修改readcount變量。因此需要一個互斥對象mutex來實現(xiàn)對全局變量readcount修改時的互斥。另外,為了實現(xiàn)寫一寫互斥,需要增加一個臨界區(qū)對象RP_Write。當寫者發(fā)出寫請求時,必須申請臨界區(qū)對象的所有權。通過這種方法,也可以實現(xiàn)讀一寫互斥、當readcount=1時(即第一個讀者到來時),讀者線程也必須申請臨界區(qū)對象的所有權。當讀者擁有臨界區(qū)的所有權時,寫者阻塞在臨界區(qū)對象RP_Write上。當寫者擁有臨界區(qū)的所有權時,第一個讀者判斷完“readcount==1”后阻塞在write上,其余的讀者由于等待對readcount的判斷,阻塞在mutex上。寫者優(yōu)先(請根據(jù)自己編寫的寫者優(yōu)先程序進行分析)四、相關API函數(shù)說明CreateThread函數(shù)功能:該函數(shù)創(chuàng)建一個在調用進程的地址空間中執(zhí)行的線程。函數(shù)原型:HANDLECreateThread(LPSECURITY_ATTRIBUTESIpThreadAttributes,DWORDdwStackSize,LPTHREAD_START_ROUTINElpStartAddress,LPVOIDlpParameter,DWORDdwCreationFlags,LPDWORDlpThreadId);參數(shù):IpThreadAttributes:指向一個LPSECURITY_ATTRIBUTES結構。該結構決定了返回的句柄是否可被子進程繼承。若lpThreadAttributes為NULL則句柄不能被繼承。在WindowsNT中該結構的lpSecurityDescriptor成員定義了新進程的安全性描述符。若lpThreadAttributes為NULL。則線程獲得一個默認的安全性描述符。-dwStackSize:定義原始堆棧提交時的大小(按字節(jié)計)。系統(tǒng)將該值舍入為最近的頁。若該值為0,或小于默認時提交的大小,默認情況是使用與調用線程同樣的大小.更多的信息,請看ThreadStackSize0?lpStartAddress指向一個LPTHREAD_START_ROUTINE類型的應用定義的函數(shù),該線程執(zhí)行此函數(shù)。該指針還表示遠程進程中線程的起始地址。該函數(shù)必須存在于遠程進程中。lpParameter:定義一個傳遞給該進程的32位值。dwCreationFlags:定義控制進程創(chuàng)建的附加標志。若定義了CREATE_SUSPENDED標志,線程創(chuàng)建時處于掛起狀態(tài),并且直到ResumeThread函數(shù)調用時才能運行。若該值為0,則該線程在創(chuàng)建后立即執(zhí)行。lpThreadId:指向一個32位值,它接收該線程的標識符。返回值:若函數(shù)調用成功,返回值為新線程的句柄;若函數(shù)調用失敗,返回值為NULL。備注:新進程的句柄創(chuàng)建時設為THREAD_ALL_ACCESS訪問權限。若未提供安全性描述符,則該句柄可被任何要求一個線程對象句柄的函數(shù)所使用。若提供了安全性描述符,則以后使用該句柄時,將在授權訪問以前執(zhí)行訪問檢查。若訪問檢查拒絕訪問,則請求進程不能使用該句柄獲得對該線程的訪問。線程從lpStartAddress參數(shù)定義的函數(shù)處開始執(zhí)行。若該函數(shù)返回,系統(tǒng)將默認地認為以調用ExitThread函數(shù)的方法終止該線程。使用GetExitcodeThread函數(shù)來獲得線程的返回值。線程創(chuàng)建時擁有THREAD_PRIORITY_NORMAL優(yōu)先權。使用GetThreadPriority和SetThreadPriority函數(shù)可以獲得和設置線程的優(yōu)先權值。一個線程終止時。該線程對象被設為發(fā)信號狀態(tài),以滿足在該對象上等待的所有進程。一個線程對象始終存在于系統(tǒng)中,直到該線程終止,且它所有的句柄都已通過調用CloseHandle函數(shù)關閉。ExitThread函數(shù)功能:該函數(shù)結束一個線程。函數(shù)原型:VOIDExitThread(DWORDdwExitCode);參數(shù):dwExitCode:定義調用線程的退出代碼。使用GetExitCodeThread函數(shù)來檢測一個線程的退出代碼。返回值:無。備注:調用ExitThread函數(shù),是結束一個線程的較好的方法。調用該函數(shù)后(或者直接地調用,或者從一個線程過程返回),當前線程的堆棧取消分配,線程終止。若調用該函數(shù)時,該線程為進程的最后一個線程,則該線程的進程也被終止。線程對象的狀態(tài)變?yōu)榘l(fā)信號狀態(tài),以釋放所有正在等待該線程終止的其他線程。線程的終止狀態(tài)從STILL_ACTIVATE變?yōu)閐wExitCode參數(shù)的值。線程結束時不必從操作系統(tǒng)中移去該線程對象。當線程的最后一個句柄關閉時,該線程對象被刪除。3.Sleep函數(shù)功能:該函數(shù)對于指定的時間間隔掛起當能的執(zhí)行線程。函數(shù)原型:VOIDSleep(DWORDdwMulliseconds);參數(shù):-dwMilliseconds:定義掛起執(zhí)行線程的時間,以毫秒(ms)為單位。取值為0時,該線程將余下的時間片交給處于就緒狀態(tài)的同一優(yōu)先級的其他線程。若沒有處于就緒狀態(tài)的同一優(yōu)先級的其他線程,則函數(shù)立即返回,該線程繼續(xù)執(zhí)行。若取值為INFINITE則造成無限延遲。返回值:該函數(shù)沒有返回值。備注:一個線程可以在調用該函數(shù)時將睡眠時間設為0ms,以將剩余的時間片交出。CreateMutex函數(shù)功能:該函數(shù)創(chuàng)建有名或者無名的互斥對象。函數(shù)原型:HANDLECreateMutex(LPSECURITY_ATTRIBUTESlpMutexAttributes,BOOLbInitialOwner,LPCTSTRlpName);參數(shù):?lpMutexAttributes:指向SECURITY_ATTRIBUTES結構的指針,該結構決定子進程是否能繼承返回句柄。如果lpMutexAttributes為NULL,那么句柄不能被繼承。在WindowsNT中該結構的LpSecuriyDescriptor成員指定新互斥對象的安全描述符。如果lpMutexAttributes為NULL,那么互斥對象獲得默認的安全描述符。-bInitialOwner:指定互斥對象的初始所屬身份。如果該值為TRUE,并且調用者創(chuàng)建互斥對象,那么調用線程獲得互斥對象所屬身份。否則,調用線程不能獲得互斥對象所屬身份。判斷調用者是否創(chuàng)建互斥對象清參閱返回值部分。?lpName:指向以NULL結尾的字符串,該字符串指定了互斥對象名。該名字的長度小于MAX_PATH且可以包含除反斜線(\)路徑分隔符以外的任何字符。名字是區(qū)分大小寫的。如果lpName與已存在的有名互斥對象名相匹配,那么該函數(shù)要求用MUTEX_ALL_ACCESS權限訪問已存在的對象。在這種情況下,由于參數(shù)bInitialOwner已被創(chuàng)建進程所設置,該參數(shù)被忽略。如果參數(shù)lpMutexAttributes不為NULL,它決定句柄是否解除繼承,但是其安全描述符成員被忽略。如果lpName為NULL,那么創(chuàng)建的互斥對象無名。如果lpName與已存在的事件、信號量、可等待定時器、作業(yè)或者義件映射對象的名字相匹配,那么函數(shù)調用失敗,并且GetLastError函數(shù)返回ERROR_ALREADY_HANDLE,其原因是這些對象共享相同的名字空間。返回值:如果函數(shù)調用成功,返回值是互斥對象句柄;如果函數(shù)調用之前,有名互斥對象已存在,那么函數(shù)給已存在的對象返回一個句柄,并且函數(shù)GetLastError返回ERROR_ALREADY_EXISTS。否則,調用者創(chuàng)建互斥對象。如果函數(shù)調用失敗,則返回值為NULL。若想獲得更多錯誤信息,請調用GetLastError函數(shù)。備注:由函數(shù)CreateMutex返回的句柄有MUTEX_ALL_ACCESS權限可以去訪問新的互斥對象,并且可用在請求互斥對象句柄的任何函數(shù)中。調用進程中的任何線程可以在調用等待函數(shù)時指定互斥對象句柄。當指定對象的狀態(tài)為信號態(tài)時。返回單對象等待函數(shù)。當任何一個或者所有的互斥對象都為信號態(tài)時,返回多對象等待函數(shù)指令。等待函數(shù)返回后,等待的線程被釋放,繼續(xù)向下執(zhí)行。當一個互斥對象不被任何線程擁有時,處于信號態(tài)。創(chuàng)建該對象的線程可以使用blnitialOwner標志來請求立即獲得對該互斥對象的所有權。否則,線程必須使用等待函數(shù)來請求所有權。當互斥對象處于信號態(tài),等待的線程獲得對該對象的所有權時,此互斥對象的狀態(tài)被設置為非信號態(tài),等待函數(shù)返回。任意時刻,僅有一個線程能擁有該互斥對象.線程可以使用ReleaseMutex函數(shù)來釋放對這個互斥對象的所有權??偩€程已經擁有了一個互斥對象,那么它可以重復調用等待函數(shù)而不會發(fā)生阻塞,一般情況下,用戶不會重復等待同一個互斥對象,這種機制防止了線程因等待它已經擁有的互斥對象而發(fā)生死鎖。然而,線程必須為每一次等待調用一次ReleaseMutex函數(shù)來釋放該互斥對象。兩個或多個進程可以調用CreateMutex來創(chuàng)建同名的互斥對象,第一個進程實際創(chuàng)建互斥對象.以后的進程打開已存在的互斥對象的句柄。這使得多個進程可以得到同一個互斥對象的句柄,從而減輕了用戶的負擔,使用戶不必判斷創(chuàng)建進程是否為第一個啟動的進程。使用這種技術時,應該把blnitialOwner標志設為FALSE否則很難確定開始時哪一個進程擁有該互斥對象。由于多進程能夠擁有相同互斥對象的句柄,通過使用這個對象,可使多進程同步。以下為共享對象機制:?如果CreateMutex中的lpMutexAttributes參數(shù)允許繼承,由CreateProcess函數(shù)創(chuàng)建的子進程可以繼承父近程的互斥對象句柄。一個進程可以在調用DuplicateHandle函數(shù)時指定互斥對象句柄來創(chuàng)建一個可以被其他進程使用的雙重句柄。一個進程在調用OpenMutex或CreateMutex函數(shù)時能指定互斥對象名。?使用CloseHandle函數(shù)關閉句柄,進程結束時系統(tǒng)自動關閉句柄。當最后一個句柄被關閉時,互斥對象被銷毀。ReleaseMutex函數(shù)功能:該函數(shù)放棄指定互斥對象的所有權。函數(shù)原型:BOOLReleaseMutex(HANDLEhMutex);參數(shù):hMutex:互斥對象句柄。為CreateMutex或OpenMutex函數(shù)的返回值。返回值:如果函數(shù)調用成功,那么返回值是非零值;如果函數(shù)調用失敗,那么返回值是零值。若想獲得更多錯誤信息,請調用GetLastError函數(shù)。備注:如果調用線程不擁有互斥對象,ReleaseMutex函數(shù)失敗。一個線程通過調用等待函數(shù)擁有互斥對象。創(chuàng)建該互斥對象的線程也擁有互斥對象。而不需要調用等待函數(shù)。當互斥對象的所有者線程不再需要互斥對象時,它可以調用ReleaseMutex函數(shù)。當一個線程擁有一個互斥對象后,它可以用該互斥對象多次調用等待函數(shù)而不會阻塞。這防止一個線程等待一個它已擁有的互斥對象時出現(xiàn)死鎖。不過,為了釋放所有權,該線程必須為每一個等待操作調用一次ReleaseMutex函數(shù);WaitForSingleObject函數(shù)功能:當下列情況之一發(fā)生時該函數(shù)返回:(1)指定對象處于信號態(tài);(2)超時。函數(shù)原型:DWORDWaitForSingleObject(HANDLEhHandle,DWORDdwMilliseconds);參數(shù):hHandle:等待對象句柄。若想了解指定句柄的對象類型列表,參閱下面?zhèn)渥⒉糠?。在WindowsNT中,句柄必須有SYNCHRONIZE訪問權限。若想獲得更多的信息,請查看StandardAccessRights。dwMilliseconds:指定以毫秒為單位的超時間隔。如果超時,即使對象的狀態(tài)是非信號態(tài)的并且沒有完成,函數(shù)也返回。如果dwMillseconds是0,函數(shù)測試對象的狀態(tài)并立刻返回;如果dwMillseconds是INFINITE,函數(shù)從不超時。返回值:如果函數(shù)調用成功,返回值表明引起函數(shù)返回的事件??赡苤等缦拢篧AIT_ABANDONED指定對象是互斥對象,在線程被終止前,線程沒有釋放互斥對象?;コ鈱ο蟮乃鶎訇P系被授予調用線程,并且該互斥對象被置為非信號態(tài)。WAIT_OBJECT_0:指定對象的狀態(tài)被置為信號態(tài)。WAIT_TIMEOUT:超時,并且對象的狀態(tài)為非信號態(tài)。如果函數(shù)調用失敗,返回值是WAIT_FAILED。若想獲得更多錯誤信息,請調用GetLastError函數(shù)。備汪:WaitForSingleObjects函數(shù)決定等待條件是否被滿足。如果等待條件并沒有被滿足,調用線程進入一個高效的等待狀態(tài),當?shù)却凉M足條件時占用非常少的處理器時間。在運行前。一個等待函數(shù)修改同步對象類型的狀態(tài)。修改僅發(fā)生在引起函數(shù)返回的對象身上。例如,信號得計數(shù)減1。WaitForSingleObjects函數(shù)能等待的對象包括:Changenotification(改變通告):Consoleinput(控制臺輸入);Event(事件);Job(作業(yè));Mutex(互斥對象);Process(進程);Semaphore(信號量);Thread(線程);Waitabletimer(可等待定時器)。當使用等待函數(shù)或代碼直接或間接創(chuàng)建窗口時,一定要小心。如果一個線程創(chuàng)建了任何窗口,它必須處理進程消息。消息廣播被發(fā)送到系統(tǒng)的所有窗口。一個線程用沒有超時的等待函數(shù)也許會引起系統(tǒng)死鎖。間接創(chuàng)建窗口的兩個例子是DDE和COMCoInitialize。因此,如果用戶有一個創(chuàng)建窗口的線程,用MsgWaitForMultipleObjects或MsgWaitForMultipleObjectEx函數(shù),而不要用SignalObjectAndWait函數(shù)。WaitForMultipleObjects函數(shù)功能:WaitForMultipleObjects函數(shù)當下列條件之一滿足時返回:(1)任意一個或全部指定對象處于信號態(tài);(2)超時間隔已過。函數(shù)原型:DWORDWaitForMultipleObjects(DWORDnCount,CONSTHANDLE*lpHandles,BOOLfWaitAll,DWORDdwMilliseconds);參數(shù):nCount:指定由lpHandles所指向的數(shù)組中的句柄對象數(shù)目最大對象句柄數(shù)目MAXIMUM_WAIT_OBJECTS。lpHandles:指向對象句柄數(shù)組的指針。該數(shù)組可以包含不同類型對象的句柄。在WindowsNT中,該句柄必須有SYNCHRONIZE訪問權限。若想獲得更多的信息,請查看StandardAccessRights0fWaitAll:指定等待類型。如果為TRUE,當lpHandles指向的數(shù)組里的全部對象為信號態(tài)時,函數(shù)返回。如果為FALSE,當由lpHandles指向的數(shù)組里的任一對象為信號態(tài)時,函數(shù)返回。對于后者,返回值指出引起函數(shù)返回的對象。dwMilliseconds:指定以毫秒為單位的超時間隔。如果超時,即使bWaitAll參數(shù)指定的條件沒有滿足,函數(shù)也返回。如果dwMilliseconds是0,函數(shù)測試指定對象的狀態(tài)并立刻返回。如果dwMilliseconds是INFINITE,函數(shù)從不超時。返回值;如果函數(shù)調用成功,返回值表明引起函數(shù)返回的事件。可能值如下:WAIT_OBJECT_0到WAIT_OBJECT0+nCount-1:如果bWaitAll為TRUE,那么返回值表明所有指定對象的狀態(tài)為信號態(tài)。如果bWaitAll為FALSE,那么返回值減去WAIT_OBJECT_0表明引起函數(shù)返回的對象的pHandles數(shù)組索引。如果多于一個對象變?yōu)樾盘枒B(tài),則返回的是數(shù)組索引最小的信號態(tài)對象索引。WAIT_ABANDONED_0到WAIT_ABANDONED_0+nCount-1:如果bWaitAll為TRUE,那么返回值表明所有指定對象的狀態(tài)為信號態(tài),并且至少一個對象是己放棄的互斥對象。如果bWaitAll為FALSE,那么返回值減去WAIT_ABANDONED_0表明引起函數(shù)返回的放棄互斥對象的pHandles數(shù)組索引。WAIT_TIMEOUT:超時并且由參數(shù)bWaitAll指定的條件沒有滿足。如果函數(shù)調用失敗,返回值是WAIT_FAILED。若想獲得更多錯誤信息,請調用GetLastError函數(shù)。CreateSemapore函數(shù)功能:該函數(shù)是創(chuàng)建一個有名或者無名信號對象。函數(shù)原型:HANDLECreatSemaphore(LPSECURITY_ATTRIBUTESIpAttributes,LONGlInitialCount,LONGlMaximumCount,LPCTSTRlpName);參數(shù);LpAttributes:安全屬性。如果是NULL就表示要使用默認屬性。lInitialCount:Semaphore的初值。必須大于或等于0,并且小于或等于MaxmumCount。lMaximumCount:Semaphore的最大值。這也就是在同一時間內能夠鎖住Semaphore之線程的最多個數(shù)。?lpNameSemaphore的名稱(一個字符串)。任何線程(或進程)都可以根據(jù)這一名稱引用到這個Semaphore0這個值可以是NULL,意思是產生一個沒有名字的Semaphoreo返回值:如果成功就傳回一個handle,否則傳回NULL。不論哪一種情況,GetLastError都會傳回一個合理的結果。如果指定的Semaphore名稱已經存在,則該函數(shù)還是成功的,GetLastError會傳回ERROR_ALREADY_EXISTS。ReleaseSemaphore函數(shù)功能:該函數(shù)將指定信號對象的計數(shù)增加一個指定的數(shù)量。函數(shù)原型:BOOLReleaseSemaphore(HANDLEhSemaphore,LONGlReleaseCount,LPLONGlpPreviousCount);參數(shù):hSemaphore:Semaphore的handle。lReleaseCount:Semaphore現(xiàn)值的增額。該值不可以是負值或0。lpPreviousCount:借此返回Semaphore原來的值。返回值:如果成功,則返回TRUE。否則返回FALSEo失敗時可調用GetLastError獲得原因。無論ReleaseSemaphore對于Semaphore所造成的當前值怎樣增加,都絕對不會超過CreateSemaphore時所指定的1MaximumCounto請記住,lpPreviousCount所傳回來的是一個瞬間值。你不可以把1ReleaseCount加上lpPreviousCount,就當做是semaphore的當前值,因為其他線程可能已經改變了Semaphore的值。與mutex不同的是,調用ReleaseSemaphore的那個線程,并不一定就是調用WaitXxx的那個線程。仟何線程都可以在任何時間調用ReleaseSemaphore,解除被任何線程鎖定的Semaphoreo10.InitializeCriticalSection函數(shù)功能:該函數(shù)初始化臨界區(qū)對象:函數(shù)原型:VOIDInitializeCriticalSection(LPCRITIAL_SECTIONlpCriticalSection);參數(shù):lpCritialSection:指向臨界區(qū)對象的指針。備注:單進程的所有線程可以使用互斥同步機制的臨界區(qū)對象。但是,不能保證線程獲得臨界區(qū)所有權的順序,系統(tǒng)將對所有線程公平處理。進程負責分配臨界區(qū)對象使用的存儲空間,這可以通過聲明CRITICAL_SECTION類型的變量來完成。在使

用臨界區(qū)之前,該進程的一些線程必須使用InitializeCriticalSection或InitializeCriticalSectionAndSpinCount函數(shù)來初始化該臨界區(qū)對象。11.EnterCriticalSection函數(shù)功能:該函數(shù)是等待指定臨界區(qū)對象的所有權。當調用線程被賦予所有權時,該函數(shù)返回。函數(shù)原型:VOIDEnterCriticalSection(LPCRITICAL_SECTIONlpCriticalSecrion);參數(shù):?IpCriticalSecrion:指間臨界區(qū)對象的指針。12.LeaveCriticalSection函數(shù)功能:該函數(shù)釋放指定臨界區(qū)對象的所有權。函數(shù)原型:VOIDLeaveCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);參數(shù);?IpCriticalSecrion:指向臨界區(qū)對象的指針。五、參考源代碼下面的程序已經在Windows2000上實現(xiàn)。用VC6.0創(chuàng)建源文件,將輸入文件命名為thread.dat并放在與源文件相同的文件夾內,編譯運行即可。#include"windows.h”#include<conio.h>#include<stdlib.h>#include<fstream.h>#include<io.h>#include<string.h>#include<stdio.h>〃讀者〃寫者〃讀者〃寫者〃每秒時鐘中斷數(shù)目〃最大線程數(shù)目〃最大數(shù)據(jù)文件數(shù)目〃字符串長度#defineWRITER'W'#defineINTE_PER_SEC1000#defineMAX_THREAD_NUM64#defineMAX_FILE_NUM32#defineMAXSTRLEN32〃讀者數(shù)目〃寫者數(shù)目〃讀者數(shù)目〃寫者數(shù)目intwritecount=0;CRITICAL_SECTIONRP_Write;〃臨界區(qū)CRITICAL_SECTIONcs_Write;CRITICAL_SECTIONcs_Read;〃線程序號〃線程類別(判斷是讀者線程還是寫者線程)〃線程序號〃線程類別(判斷是讀者線程還是寫者線程)〃線程延遲〃線程寫操作持續(xù)時間};//////////////////////////////////////////////////〃讀者優(yōu)先 讀者線程//P:讀者線程信息voidRP_ReaderThread(void*p){〃互斥變量HANDLEh_Mutex;h_Mutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"mutex_for_redcount");DWORDwait_for_mutex; 〃等待互斥變量所有權DWORDm_delay; 〃延遲時間DWORDm_persist; 〃讀文件持續(xù)時間intm_serial; 〃線程序號〃從參數(shù)中獲得信息m_serial=((ThreadInfo*)(p))->serial;m_delay=(DWORD)(((ThreadInfo*)(p))->delay*INTE_PER_SEC);m_persist=(DWORD)(((ThreadInfo*)(p))->persist*INTE_PER_SEC);Sleep(m_delay); 〃延遲等待printf("Readerthread%dsentsthereadingrequire.\n”,m_serial);〃等待互斥信號,保證對readcount的訪問、修改互斥wait_for_mutex=WaitForSingleObject(h_Mutex,-1);〃讀者數(shù)目增加readcount++;if(readcount==1){〃第一個讀者,等待資源EnterCriticalSection(&RP_Write);}ReleaseMutex(h_Mutex); 〃釋放互斥信號//讀文件printf("Readerthread%dbeginstoreadfile.\n”,m_serial);Sleep(m_persist);〃退出線程printf("Readerthread%dfinishedreadingfile.\n”,m_serial);〃等待互斥信號,保證對readcount的訪問、修改互斥wait_for_mutex=WaitForSingleObject(h_Mutex,-1);〃讀者數(shù)目減少readcount--;

if(readcount==0){〃如果所有的者讀完,喚醒寫者LeaveCriticalSection(&RP_Write);}ReleaseMutex(h_Mutex); 〃釋放互斥信號}//////////////////////////////////////////////////〃讀者優(yōu)先一一寫者線程//P:寫者線程信息voidRP_WriterThread(void*p){DWORDm_delay; 〃延遲時間DWORDm_persist; 〃寫文件持續(xù)時間intm_serial; 〃線程序號〃從參數(shù)中獲得信息m_serial=((ThreadInfo*)(p))->serial;m_delay=(DWORD)(((ThreadInfo*)(p))->delay*INTE_PER_SEC);m_persist=(DWORD)(((ThreadInfo*)(p))->persist*INTE_PER_SEC);Sleep(m_delay); 〃延遲等待printf("Writerthread%dsentthewrintingrequire.\n",m_serial);〃等待資源EnterCriticalSection(&RP_Write);//寫文件printf("Writerthread%dbeginstowritetothefile.\n",m_serial);Sleep(m_persist);〃退出線程printf("Writerthread%dfinishingwritingtothefile.\n”,m_serial);//釋放資源LeaveCriticalSection(&RP_Write);}//////////////////////////////////////////////////〃讀者優(yōu)先處理函數(shù)//file:文件名〃線程數(shù)目〃線程ID〃線程數(shù)目〃線程ID〃等待所有線程結束DWORDn_thread=0;DWORDthread_ID;DWORDwait_for_all;〃互斥對象HANDLEh_Mutex;h_Mutex=CreateMutex(NULL,FALSE,"mutex_for_readcount");〃線程對象的數(shù)組HANDLEh_Thread[MAX_THREAD_NUM];ThreadInfothread_info[MAX_THREAD_NUM];readcount=0; 〃初始化readcountInitializeCriticalSection(&RP_Write);〃初始化臨界區(qū)ifstreaminFile;inFile.open(file); 〃打開文件printf("ReaderPriority:\n\n");while(inFile){〃讀入每一個讀者、寫者的信息inFile>>thread_info[n_thread].serial;inFile>>thread_info[n_thread].entity;inFile>>thread_info[n_thread].delay;inFile>>thread_info[n_thread++].persist;inFile.get();}for(inti=0;i<(int)(n_thread);i++){if(thread_info[i].entity==READER||thread_info[i].entity=='r'){〃創(chuàng)建讀者線程h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(RP_ReaderThread),&thread_info[i],0,&thread_ID);}else〃創(chuàng)建寫者線程h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(RP_WriterThread),&thread_info[i],0,&thread_ID);}〃等待所有線程結束wait_for_all=WaitForMultipleObjects(n_thread,h_Thread,TRUE,-1);printf("Allreaderandwriterhavefinishedoperating.");}/////////////////////////////////////////////////〃寫者優(yōu)先——讀者線程//P:讀者線程信息voidWP_ReaderThread(void*p){〃請編寫寫者優(yōu)先的讀者線程}//////////////////////////////////////////////〃寫者優(yōu)先一一寫者線程//P:寫者線程信息voidWP_WriterThread(void*p){//請編寫寫者優(yōu)先的寫者線程}////////////////////////////////////////////////〃寫者優(yōu)先處理函數(shù)//file:文件名voidWriterPriority(char*file){//請編寫寫者優(yōu)先處理函數(shù)}///////////////////////////////////////////////////〃主函數(shù)intmain(intargc,char*argv[]){charch;while(true){〃打印提示信息printf("*********************************************\n");printf(" 1:ReaderPriority\n");printf(" 2:WriterPriority\n");printf(" 3:ExittoWindows\n");printf("*********************************************\n");printf("Enteryourchoice(1,2or3):");〃如果輸入信息不正確,繼續(xù)輸入do{ch=(char)_getch();}while(ch!=T&&ch!='2'&&ch!='3');system("cls");〃選擇3,返回if(ch=='3')return0;〃選擇1,讀者優(yōu)先elseif(ch=='1')ReaderPriority("thread.dat");〃選擇2,寫者優(yōu)先elseWriterPriority("thread.dat");〃結束printf("\nPressAnyKeyToContinue:");_getch();system("cls");}return0;}說明:在Win32API中,互斥對象Mutex與P、V中的互斥信號量有類似的地方,但也有不同:在P、V操作中的互斥信號量可以有一個任意大小的初值,但互斥對象Mutex沒有,它可以被看成是初值為1的互斥信號量。而且一個線程在取得Mutex的所有權之后,即使不調用ReleaseMutex函數(shù),在線程結束時,線程也會自動釋放Mutex的所有權。臨界區(qū)對象CriticalSection則與P、V操作中初值為1的互斥信號量語意相同。它在線程結束時,會將CriticalSection的所有權傳遞結它的向類型線程。這樣就可以滿足在一個線程中申請所有權,在另一個線程釋放所有權的要求。在讀者優(yōu)先中的write互斥信號號以及寫者優(yōu)先中的read和write互斥信號量就應該用CriticalSection實現(xiàn)而不應該用Mutex。用WairForSingleSigna1函數(shù)可以獲得一個Mutex的所有權,類似于P操作,而ReleaseMutex函數(shù)可以釋放一個Mutex的所有權,類似于V操作。用EnterCriticalSection函數(shù)可以進入一個CriticalSectin,類似于P操作,而LeaveCriticalSection函數(shù)離開一個CriticalSection,類似于V操作。備注:ReaderPriority函數(shù)最后有Wait_for_all=WaitForMultipleObject(n_thread,h_Thread,TRUE,-1);是因為主函數(shù)要等待所有的線程都結束之后才退出。因為不知道有多少線程,所以源文件最初有:#defineMAX_THREAD_NUM64 〃最大線程數(shù)目即線程最多不能超過MAX_THREAD_NUM個。線程對象的數(shù)組大小為MAX_THREAD_NUM。如果創(chuàng)建的線程沒有這么多,空間會有浪費,但是可以達到犧牲空間來節(jié)省時間的目的。有的書上還有其他的處理方法。一種是在主函數(shù)的最后加上Sleep(1000),即通過主函數(shù)睡眠的方法等待其他進程結束,這當然不是一種很好的方法,因為睡眠等待的時間沒法控制。另一種方法是增加循環(huán)變量threadCount(線程的個數(shù)),每個線程結束的時候就會執(zhí)行語句threadCount--;主函數(shù)的最后測試:while(threadCount>0);但是這種方式會讓主函數(shù)循環(huán)等待,浪費了CPU資源。相比之下,考慮到運行效率,還是實例中給出的方法比較好些。六、示例程序的結果分析對數(shù)據(jù)文件thread.dat進行分析:TOC\o"1-5"\h\zR35W45R52R65W5.13讀者優(yōu)先結果:ReaderPriority:Readerthread1sentsthereadingrequire.Readerthread1beginstoreadfile.Writerthread2sentthewrintingrequi

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論