操作系統(tǒng)-創(chuàng)建線程,利用互斥實現(xiàn)線程共享變量通信_第1頁
操作系統(tǒng)-創(chuàng)建線程,利用互斥實現(xiàn)線程共享變量通信_第2頁
操作系統(tǒng)-創(chuàng)建線程,利用互斥實現(xiàn)線程共享變量通信_第3頁
操作系統(tǒng)-創(chuàng)建線程,利用互斥實現(xiàn)線程共享變量通信_第4頁
操作系統(tǒng)-創(chuàng)建線程,利用互斥實現(xiàn)線程共享變量通信_第5頁
已閱讀5頁,還剩20頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

創(chuàng)建線程,利用互斥實現(xiàn)線程共享變量通信l=JI三三概述1.1課題目的和意義掌握線程創(chuàng)建和終止,加深對線程和進程概念的理解,會用同步與互斥方法實現(xiàn)線程之間的通信。1.2內(nèi)容和要求軟件界面上點“創(chuàng)建線程”按鈕,創(chuàng)建三個生產(chǎn)者線程(P1,P2,P3)和兩個消費者線程(C1,C2),生產(chǎn)者和消費者線程共享一個長度為2KB的環(huán)型公共緩沖區(qū),生產(chǎn)者向其中投放消息,消費者從中取走消息。只要緩沖區(qū)未滿,生產(chǎn)者可將消息送入緩沖區(qū);只要緩沖區(qū)未空,消費者可從緩沖區(qū)取走一個消息。每個消息具下列結(jié)構(gòu)格式:消息頭(1B,固定為0xaa),消息長度(1B),消息內(nèi)容(nB),校驗和(1B),檢驗和計算方式為消息長度和消息內(nèi)容所有字節(jié)異或結(jié)果。每個生產(chǎn)者每隔n毫秒(n用隨機數(shù)產(chǎn)生,1到100毫秒之間,間隔不固定)生產(chǎn)一個消息加入緩沖區(qū),并把消息產(chǎn)生時間和內(nèi)容記錄在一個文本文件中(或顯示在列表框中)。P1每次生產(chǎn)的數(shù)據(jù)為26個大寫字母,P2每次生產(chǎn)的數(shù)據(jù)為26個小寫字母,P3每次生產(chǎn)的數(shù)據(jù)為10個數(shù)字。每個消費者每隔n秒(n用隨機數(shù)產(chǎn)生,1到5秒之間,間隔不固定)從緩沖區(qū)取走一個消息。每消費一個消息需要將消費時間和消息內(nèi)容記錄在一個文本文件中(或顯示在列表框中)。當用戶按結(jié)束按鈕時結(jié)束5個線程,并將5個文件內(nèi)容顯示出來進行對照。這期實是一個經(jīng)典的生產(chǎn)者一消費者(Producer_consumer)進程(線程)同步的問題。它描述的是:有一群生產(chǎn)者進程在生產(chǎn)產(chǎn)品,并將此產(chǎn)品提供給消費者進程(線程)去消費。為使生產(chǎn)者進程和消費者進程(線程)能并發(fā)執(zhí)行,在它們之間設(shè)置有個緩沖區(qū)的緩沖池,生產(chǎn)者進程(線程)可將它所生產(chǎn)的產(chǎn)品放入一個緩沖區(qū)中,消費者進程(線程)可從一個緩沖區(qū)取得一個產(chǎn)品消費。盡管所有的生產(chǎn)者進程和消費者進程(線程)都是以異步的方式運行的,但它們之間必須保持同步,即不允許消費者進程(線程)到一個空緩沖區(qū)去取產(chǎn)品,也不允許生產(chǎn)者進程(線程)向一個已裝有消息尚未被取走產(chǎn)品的緩沖區(qū)投放產(chǎn)品。如下圖所示:生產(chǎn)者01VI…叩生產(chǎn)者2 L --一m --生產(chǎn)者k~—(IIIII口個大小相等的緩沖區(qū),每個緩沖區(qū);彳存放一個消息1.3線程所采用的同步方法同步是多線程中的重要概念.同步的使用可以保證在多線程運行的環(huán)境中,程充不會產(chǎn)生設(shè)計之外的結(jié)果.同步的實現(xiàn)方式有兩種,同步方法和同步塊.線程在執(zhí)行同步方法是具有排它性的.當任意一個線和進入到一個對象的任意一個同步方法時,這個對象所有同步方法都被鎖定,在些期間,期他任何線程都不能訪問這個對象的任意一個同步方法,直到這個線程執(zhí)行完它所調(diào)用的同步方法并從中退出,從而導(dǎo)至它釋放了該對象的同步鎖這后.在一個對象被某個線程鎖定之后,其他線程是可以訪問.同步的有幾種實現(xiàn)方法,分別是:wait():使一個線程處于等待狀態(tài),并且釋放所有持有的對象1ock.s1eep():使一個正在運行的線程處于睡眠狀態(tài),是一個靜態(tài)方法,調(diào)用此方法要捕捉InterruptedException異常。notify。:喚醒一個處于等待狀態(tài)的線程,注意的是在調(diào)用此方法的時候,并不能確切的喚醒某一個等待狀態(tài)的線程,而是由JVM確定喚醒哪個線程,而且不是按優(yōu)先級。Allnotity():喚醒所有處入等待狀態(tài)的線程,注意并不是給所有喚醒線程一個對象的鎖,而是讓它們競爭。1.4開發(fā)工具平臺開發(fā)平臺:windowXP開發(fā)工具:VC++數(shù)據(jù)定義和詳細說明1數(shù)據(jù)定義設(shè)計PV操作算法,用信號量機制實現(xiàn)生產(chǎn)者與消費者同步與互斥問題,并與無PV情況下進行對比。定義20個緩沖區(qū),將其初始化為0。調(diào)用隨機函數(shù)rand()生成隨機數(shù),把隨機數(shù)通過生產(chǎn)者放入緩沖區(qū)。若緩沖區(qū)滿則其值非0。當消費者從緩沖區(qū)中去數(shù)后緩沖區(qū)值變?yōu)?。程序可顯示緩沖區(qū)中的全部內(nèi)容,方便觀察生產(chǎn)者與消費者的行為。程序可通過設(shè)置sleep(time)中time的值來控制生產(chǎn)者與消費者的執(zhí)行順序。2詳細說明為了實現(xiàn)生產(chǎn)者與消費者同步與互斥的問題,該程序用記錄型信號量機制來實現(xiàn)。假定在生產(chǎn)者與消費者之間,利用一個公共的緩沖池來進行通信,生產(chǎn)者將所生產(chǎn)的信息放入其中,消費者cognitive緩沖池中取得消息來消費,該緩沖池具有n個緩沖區(qū),其編號為0,1,2,3???,n-1;設(shè)置一個互斥信號量mutex,用于實現(xiàn)諸進程對緩沖池的互斥使用,其初值為1,利用資源信號量empty,表示緩沖池中空緩沖區(qū)的數(shù)目,其初值為n;full分別表示緩沖池中滿緩沖區(qū)的數(shù)目,其初值為0.又假定這些生產(chǎn)者和消費者相互等效,只要緩沖池未滿,生產(chǎn)者便可將消息送入由指針in所指的緩沖區(qū);只要緩沖池未空,消費者變可以從由指針out所指示的緩沖區(qū)中,取走一個消息。對生產(chǎn)者消費者的問題可以描述如下:Varmetux,empty,full:semaphore=1,n,0;Buffer:array[0,???n—1]ofitem;In,out:integer:=0;Begin:PabeginProducer:beginRepeatProduceranitemnextp;P(empty);P(mutex);buffer(in):=nextp;in:=(in+1)modn;V(mutex);V(fu11);Untilfalse;EndConsumer:beginRepeatP(ful1);P(mutex);nextc:=buffer(out);out:=(out+1)modn;V(mutex);V(empty);Untilfalse;EndParendEnd實現(xiàn)思想和設(shè)計流程1實現(xiàn)思想我們把系統(tǒng)中使用某一類資源的進程(線程)稱為該資源的消費者,而把釋放同類資源的進程稱為該資源的生產(chǎn)者。例如在計算進程(線程)與打印進程(線程)公用一個緩沖區(qū)時,計算進程(線程)把數(shù)據(jù)送入緩沖區(qū),打印進程(線程)從緩沖區(qū)中取數(shù)據(jù)打印輸出,因此,計算進程相當于數(shù)據(jù)資源的生產(chǎn)者,而打印進程相當于消費者,二者之間必須保持同步。基于這一問題,我們將使用生產(chǎn)者和消費者這一同步機制算法來處理該問題.2設(shè)計流程首先,我們知道,生產(chǎn)者一消費者問題是一個同步問題。即生產(chǎn)者和消費者之間應(yīng)滿足如下條件:2.1消費者想接收數(shù)據(jù)時,有界緩沖區(qū)中至少有一個單元是滿的。2.2生產(chǎn)者想發(fā)送數(shù)據(jù)時,有界緩沖區(qū)中至少有一個單元是空的。另外,由于有界緩沖區(qū)是臨界資源,因此,各生產(chǎn)者進程和各消費者進程之間必須互斥。其次,我們還必須考慮面臨的問題是屬于進程互斥還是進程同步,或是互斥與同步的混合問題。然后根據(jù)共享資源的數(shù)量以及使用共享資源的規(guī)則正確的定義信號量及其初值。最后,還要對結(jié)果進行分析處理。若結(jié)果中生產(chǎn)和消費進程都已處理完時,但還可能出現(xiàn)以下兩種情況:一是還有生產(chǎn)進程,但沒有空緩沖,且消費進程暫時已完,所以此時,只能結(jié)束等待新的消費進程產(chǎn)生空緩沖。二是還有消費進程,但沒有了滿緩沖,且生產(chǎn)進程暫時已完,此時,只能結(jié)束等待新的生產(chǎn)進程來輸入數(shù)據(jù),產(chǎn)生新的滿緩沖等。在程序中應(yīng)能作出相應(yīng)的判斷和處理。本程序的執(zhí)行是在C++的環(huán)境中通過手動輸入生產(chǎn)者和消費者線程的運行速度來控制程序的運行的。為了實現(xiàn)生產(chǎn)者進程能把生產(chǎn)出來的產(chǎn)品正確的存入緩沖區(qū),和消費者進程能夠從緩沖區(qū)中取產(chǎn)品進行消費,防止因等待資源而出現(xiàn)死鎖的現(xiàn)象,首先設(shè)置兩個時間:生產(chǎn)者生產(chǎn)一個產(chǎn)品后等待的時間tl,和消費者消費一個產(chǎn)品后等待的時間t2,來控制生產(chǎn)者和消費者進程執(zhí)行的速度。其函數(shù)原形是sleep(tl)和sleep(t2)其中tl、t2指定義掛起執(zhí)行線程的時間,以毫秒為單位,取值為0時,該線程將余下的時間片交給處于就緒狀態(tài)的同一優(yōu)先級的其他線程。若沒有處于就緒狀態(tài)的同一優(yōu)先級的其他線程,則函數(shù)立即返回。3程序流程圖創(chuàng)建進程模擬生產(chǎn)者消費者

退出臨界區(qū)圖3-1退出臨界區(qū)圖3-1程序流程圖4關(guān)鍵代碼分析本程序采用了MFC可視化界面來完成,現(xiàn)在給出關(guān)鍵代碼來分析.4.1開始創(chuàng)建線程原代碼:voidCMultiThreadDlg::OnStart()〃開始創(chuàng)建線程{hMutex=CreateMutex(NULL,FALSE,NULL);//創(chuàng)建互斥對象threadController=1;ocheck=TRUE;//檢測標識°HWNDhWnd=GetSafeHwnd();//得到控制權(quán)AfxBeginThread(ThreadProc,hWnd,THREAD_PR10RITY_NORMAL);//啟用生產(chǎn)者線程1(P1)oAfxBeginThread(ThreadProc2,hWnd,THREAD_PRI0RITY_NORMAL);〃啟用生產(chǎn)者線程2(P2)AfxBeginThread(ThreadProc3,hWnd,THREAD_PRIORITY_N0RMAL);//啟用生產(chǎn)者線程3(P3)AfxBeginThread(Thread_consumer,hWnd,THREAD_PRIORITY_NORMAL);〃啟用消費者線程1(S1)。AfxBeginThread(Thread_consumer2,hWnd,THREAD_PRIORITY_NORMAL);//啟用消費者線程2(S2)}原碼功能:主要創(chuàng)建生產(chǎn)者和消費者線程,創(chuàng)建互斥對象,創(chuàng)建窗體對象.主要函數(shù)功能:4.1.2CreateMutex()函數(shù)功能:該函數(shù)是創(chuàng)建有名或者無名的互斥對象。函數(shù)原型:HANDLECreateMutex(LPSECURITY_ATTRIBUTES1pMutexAttributes,BOOLblnitialOwner,LPCTSTR1pName);參數(shù):1pMutexAttributes:指向SECURITY_ATTRIBUTES結(jié)構(gòu)的指針,該結(jié)構(gòu)決定子進程是否能繼承返回句柄。如果lpMutexAttributes為NULL,那么句柄不能被繼承。在WindowsNT中該結(jié)構(gòu)的lpSecurityDescriptor成員指定新互斥對象的安全描述符。如果lPMutexAttributes為NULL,那么互斥對象獲得缺省的安全描述符。blnitialOwner:指定互斥對象的初始所屬身份。如果該值為TRUE并且調(diào)用者創(chuàng)建互斥對象,那么調(diào)用線程獲得互斥對象所屬身份。否則,調(diào)用線程不能獲得互斥對象所屬身份。判斷調(diào)用者是否創(chuàng)建互斥對象請參閱返回值部分。lPName:指向以NULL結(jié)尾的字符串,該字符串指定了互斥對象名。該名字的長度小于MAX_PATH且可以包含除反斜線路徑分隔符(\)以外的任何字符。名字是區(qū)分大小寫的。如果與已存在的有名互斥對象名相匹配,那么該函數(shù)要求用—權(quán)限訪問已存在的對象。在這種情況下,由于參數(shù)己被創(chuàng)建進程所設(shè)置,該參數(shù)被忽略。如果參數(shù)不為,它決定句柄是否解除繼承,但是其安全描述符成員被忽略。如果lpName為NULL,那么創(chuàng)建的互斥對象無名。如果1pName與已存在的事件、信號量、可等待定時器、作業(yè)、或者文件映射對象的名字相匹配,那么函數(shù)調(diào)用失敗,并且GetLastError函數(shù)返回ERPOR_INVALID_HANDLE。其原因是這些對象共享相同的名字空間。返回值:如果函數(shù)調(diào)用成功,返回值是互斥對象句柄;如果函數(shù)調(diào)用之前,有名互斥對象已存在,那么函數(shù)給已存在的對象返回一個句柄,并且函數(shù)GetLastError返回ERROR_ALREADY_EXISTS,否則,調(diào)用者創(chuàng)建互斥對象。如果函數(shù)調(diào)用失敗,則返回值為NULL。若想獲得更多錯誤信息,請調(diào)用GetLastError函數(shù)。如果CreateMutex中的1pMutexA11ributes參數(shù)允許繼承,由CreateProcess函數(shù)創(chuàng)建的子進程可以繼承父進程的互斥對象句柄。一個進程可以在調(diào)用DuplicateHandle函數(shù)時指定互斥對象句柄來創(chuàng)建一個可以被其他進程使用的雙重句柄。一個進程在調(diào)用OpenMutex或CreateMutex函數(shù)時能指定互斥對象名。使用CloseHandle函數(shù)關(guān)閉句柄,進程結(jié)束時系統(tǒng)自動關(guān)閉句柄。當最后一個句柄被關(guān)閉時,互斥對象被銷毀。GetSafeHwnd()功能:到一個窗口對象(CWnd的派生對象)指針的句柄(HWND)函數(shù)原型:HWNDhwnd=pwnd->GetSafeHwnd();函數(shù)用法:CWnd大pwnd=FindWindow(“ExploreWC1ass”,NULL);//希望找到資源管理器HWNDhwnd=pwnd->m_hwnd;〃得到它的HWND這樣的代碼當開始得到的pwnd為空的時候就會出現(xiàn)一個“Generalprotectionerror”,并關(guān)閉應(yīng)用程序,因為一般不能對一個NULL指針訪問其成員,如果用下面的代碼:CWnd*pwnd=FindWindow(“Exp1oreWClass”,NULL);//希望找到資源管理器HWNDhwnd=pwnd->GetSafeHwnd();//得到它的HWND就不會出現(xiàn)問題,因為盡管當pwnd是NULL時,GetSafeHwnd仍然可以用,只是返回NULL,通過GetSafeHwnd()的實現(xiàn)代碼就更清楚了:_AFXWIN_INLINEHWNDCWnd::GetSafeHwnd()const{returnthis==NULL?NULL:m_hWnd;} -AfxBeginThread()功能:用于創(chuàng)建工作者線程函數(shù)原型:CWinThread*AfxBeginThread(AFX_THREADPR0CpfnThreadProc,LPVOIDpParam,intnPriority=THREAD_PRIORITY_N0RMAL,UINTnStackSize=0,DWORDdwCreateFlags=0,LPSECURITY_ATTRIBUTESlpSecurityAttrs=NULL);返回值:一個指向新線程的線程對象.pfnThreadProc:線程的入口函數(shù),聲明一定要如下:UINTMyThreadFunction(LPVOIDpParam);pParam:傳遞入線程的參數(shù),注意它的類型為:LPVOID,所以我們可以傳遞一個結(jié)構(gòu)體入線程.nPriority:線程的優(yōu)先級,一般設(shè)置為0 .讓它和主線程具有共同的優(yōu)先級.nStackSize:指定新創(chuàng)建的線程的棧的大小.如果為0,新創(chuàng)建的線程具有和主線程一樣的大小的棧dwCreateFlags:指定創(chuàng)建線程以后,線程有怎么樣的標志.可以指定兩個值:CREATE_SUSPENDED:線程創(chuàng)建以后,會處于掛起狀態(tài),直到調(diào)用:ResumeThread0:創(chuàng)建線程后就開始運行.lpSecurityAttrs:指向一個SECURITY_ATTRIBUTES的結(jié)構(gòu)體,用它來標志新創(chuàng)建線程的安全性.如果為NULL,那么新創(chuàng)建的線程就具有和主線程一樣的安全性.如果要在線程內(nèi)結(jié)束線程,可以在線程內(nèi)調(diào)用AfxEndThread.4.2生產(chǎn)者線程原碼:UINTCMultiThreadDlg::ThreadProc(LPVOIDparam)//生產(chǎn)者1的生產(chǎn)過程{while(threadController){oWaitForSingleObject(hMutex,INFINITE);//等待一個同步事件的到來”if(number<20)° {o“srand((unsigned)time(NULL));//返回一個隨機數(shù)o Tntn;on=rand()%9+1;//隨機顯示字數(shù)。。Sleep(n*100);ooCStringstr;oooCString str_;oofor(inti=0;i<n;i++)//循環(huán)隨機的字數(shù)o{o oostr—.Format("%c",65+rand()%9+1);//顯示大寫字母oostr.Insert(i,str_);//插入成一列o}ooolist.AddTail(CString(str));oooCStringstring;string.Format("%s%d%s%d”,"0xaa”,n,list.GetTail(),sizeof(list.GetTail())人sizeof(n));//按格式消息頭(1B,固定為0xaa),消息長度(1B),消息內(nèi)容(nB),校驗和(1B)pbox1->AddString(string);//打印oonumber++;oo}oReleaseMutex(hMutex);//釋放互斥oo}}原碼功能:當生產(chǎn)者線程1得到控制權(quán),等待同步事件,產(chǎn)生隨機個數(shù)(n),按產(chǎn)生的隨機數(shù)顯示n個大寫字母,利用sleep函數(shù)來隔時存儲到緩沖區(qū),最后按格式消息頭(1B,固定為0xaa),消息長度(1B),消息內(nèi)容(nB),校驗和(1B)的方式輸出.主要函數(shù)功能:4.2.1 WaitForSingleObject()函數(shù)功能:當如下情況之一發(fā)生時該函數(shù)返回:指定對象處于信號態(tài);超時。函數(shù)原型:DWORDWaitForSingle0bject(HANDLEhHandle,DWORDdwMilliseconds);參數(shù):hHandle:等待對象句柄。若想了解指定句柄的對象類型列表,參閱下面說明部分。在WndowsNT中,句柄必須有SYNCHRONIZE訪問權(quán)限。若想獲得更多的信息,請查看StandardAccessRights。dwMilliseconds:指定以毫秒為單位的超時間隔。如果超時,即使對象的狀態(tài)是非信號態(tài)的并且沒有完成,函數(shù)也返回。如果dwMilliseconds是0,函數(shù)測試對象的狀態(tài)并立刻返回:如果dwMillseconds是INFINlTE,函數(shù)從不超時。返回值:如果函數(shù)調(diào)用成功,返回值表明引起函數(shù)返回的事件??赡苤等缦拢篧AUABANDONED:指定對象是互斥對象,在線程被終止前,線程沒有釋放互斥對象?;コ鈱ο蟮乃鶎訇P(guān)系被授予調(diào)用線程,并且該互斥對象被置為非信號態(tài)。WAIT_OBJECT_0:指定對象的狀態(tài)被置為信號態(tài)。WAlT_TIMEOUT:超時,并且對象的狀態(tài)為非信號態(tài)。如果函數(shù)調(diào)用失敗,返回值是WAIT_FAILED。若想獲得更多錯誤信息,請調(diào)用GetLastError函數(shù)。4.2.2ReleaseMutex()函數(shù)功能:該函數(shù)放棄指定互斥對象的擁有權(quán)。函數(shù)原型:BOOLReleaseMutex(HANDLEhMutex);參數(shù):hMutex:互斥對象句柄。為CreateMutex或OpenMutex函數(shù)的返回值。返回值:如果函數(shù)調(diào)用成功,那么返回值是非零值;如果函數(shù)調(diào)用失敗,那么返回值是零值。若想獲得更多錯誤信息,請調(diào)用GetLastError函數(shù)。備注:如果調(diào)用線程不擁有互斥對象,ReleaseMutex函數(shù)失敗。一個線程通過調(diào)用等待函數(shù)擁有互斥對象。創(chuàng)建該互斥對象的線程也擁有互斥對象,而不需要調(diào)用等待函數(shù)。當互斥對象的所有者線程不再需要互斥對象時,它可以調(diào)用ReleaseMutex函數(shù)。當一個線程擁有一個互斥對象后,它可以用該互斥對象多次調(diào)用等待函數(shù)而不會阻塞。這防止一個線程等待一個它已擁有的互斥對象時出現(xiàn)死鎖。不過,為了釋放所有權(quán),該線程必須為每一個等待操作調(diào)用一次ReleaseMutex函數(shù)。4.2.3Sleep()函數(shù)功能:該函數(shù)對于指定的時間間隔掛起當前的執(zhí)行線程。函數(shù)原型:voidSleep(DWORDdwMilliseconds);參數(shù):dwMilliseconds:定義掛起執(zhí)行線程的時間,以毫秒為單位。取值為0時,該線程將余下的時間片交給處于就緒狀態(tài)的同一優(yōu)先級的其他線程。若沒有處于就緒狀態(tài)的同一優(yōu)先級的其他線程,則函數(shù)立即返回,該線程繼續(xù)執(zhí)行。若取值為INFINITE則造成無限延遲。返回值:該函數(shù)沒有返回值。備注:一個線程可以在調(diào)用該函數(shù)時將睡眠時間設(shè)為0毫秒,以將剩余的時間片交出。使用Sleep函數(shù)和直接或間接創(chuàng)建窗口的代碼時必須非常小心。若線程創(chuàng)建了窗口,它就必須處理消息。消息廣播被發(fā)送給系統(tǒng)中的所有窗口。若有一個線程調(diào)用Sleep函數(shù)時使用了無限延遲,則系統(tǒng)會死鎖。兩個直接創(chuàng)建窗口的代碼的例子是DDE和COMCoInitialize。因此,若有一個創(chuàng)建窗口的線程,則使用MsgWaitForMutipleObjects和MsgWaitForMutipleObjectsEx函數(shù),而不使用Sleep()函數(shù)。4.2.4GetTail()函數(shù)功能:獲取此列表中的頭元素函數(shù)原型: CTypedPtrList::GetTail參數(shù):指定保存在列表中的元素類型的模板參數(shù)返回值:如果是通過一個指向constCTypedPtrList的指針訪問此列表,則GetTail返回一個類型由模板參數(shù)TYPE指定的指針。這使此函數(shù)只能被使用在賦值語句的右邊,這樣就保護了列表不被修改。如果列表被直接訪問,或通過一個指向CTypedPtrList的指針訪問,則GetTail返回對一個類型由模板參數(shù)TYPE指定的指針的引用。這使得此函數(shù)可以使用在賦值語句的任何一邊,從而允許該列表可以被修改備注:在調(diào)用GetTail之前,你必須保證該列表不是空的。如果列表是空的,則Microsoft基礎(chǔ)類庫的調(diào)試版將給出斷言。使用IsEmpty來檢驗列表是否包含元素。4.3消費者線程原碼:UINTCMultiThreadDlg::Thread_consumer(LPVOIDparam)//消費者{while(threadController)。{。WaitForSingleObject(hMutex,INFINITE);//等待同步事件oif(number>0)//緩沖區(qū)有內(nèi)容。{oosrand((unsigned)time(NULL));“intn;o n=rand()%4+1;oSleep(n*1000);//延時1—5秒ooCStringstring;string.Format("%s%d%s%d","0xaa",strlen(list.GetHead()),list.GetHead(),sizeof(list.GetTail())Asizeof(strlen(list.GetHead())));//得到緩沖區(qū)內(nèi)容spbox4->AddString(string);o1ist.RemoveHead();//刪除頭內(nèi)容snumber--;oReleaseMutex(hMutex);〃釋放互斥o}else//否則解除互斥{oRe1easeMutex(hMutex);}o}oreturn0;}原碼功能:執(zhí)行消費費線程,當緩沖區(qū)有數(shù)據(jù)時取出內(nèi)容,并且按隨機時間(1-5秒的范圍內(nèi))取數(shù),按固定的格式消息頭(1B,固定為0xaa),消息長度(1B),消息內(nèi)容(nB),校驗和(1B)做輸出.4.3.1Sleep()函數(shù)功能:該函數(shù)對于指定的時間間隔掛起當前的執(zhí)行線程。函數(shù)原型:voidSleep(DWORDdwMilliseconds);參數(shù):dwMilliseconds:定義掛起執(zhí)行線程的時間,以毫秒為單位。取值為0時,該線程將余下的時間片交給處于就緒狀態(tài)的同一優(yōu)先級的其他線程。若沒有處于就緒狀態(tài)的同一優(yōu)先級的其他線程,則函數(shù)立即返回,該線程繼續(xù)執(zhí)行。若取值為INFINITE則造成無限延遲。返回值:該函數(shù)沒有返回值。備注:一個線程可以在調(diào)用該函數(shù)時將睡眠時間設(shè)為0毫秒,以將剩余的時間片交出。使用SleeP函數(shù)和直接或間接創(chuàng)建窗口的代碼時必須非常小心。若線程創(chuàng)建了窗口,它就必須處理消息。消息廣播被發(fā)送給系統(tǒng)中的所有窗口。若有一個線程調(diào)用Sleep函數(shù)時使用了無限延遲,則系統(tǒng)會死鎖。兩個直接創(chuàng)建窗口的代碼的例子是DDE和COMCoInitia1ize。因此,若有一個創(chuàng)建窗口的線程,則使用MsgWaitForMutipleObjects和MsgWaitForMutip1eObjectsEx函數(shù),而不使用Sleep()函數(shù)。4.3.2ReleaseMutex()函數(shù)功能:該函數(shù)放棄指定互斥對象的擁有權(quán)。函數(shù)原型:BOOLReleaseMutex(HANDLEhMutex);參數(shù):hMutex:互斥對象句柄。為CreateMutex或OpenMutex函數(shù)的返回值。返回值:如果函數(shù)調(diào)用成功,那么返回值是非零值;如果函數(shù)調(diào)用失敗,那么返回值是零值。若想獲得更多錯誤信息,請調(diào)用GetLastError函數(shù)。備注:如果調(diào)用線程不擁有互斥對象,ReleaseMutex函數(shù)失敗。一個線程通過調(diào)用等待函數(shù)擁有互斥對象。創(chuàng)建該互斥對象的線程也擁有互斥對象,而不需要調(diào)用等待函數(shù)。當互斥對象的所有者線程不再需要互斥對象時,它可以調(diào)用ReleaseMutex函數(shù)。當一個線程擁有一個互斥對象后,它可以用該互斥對象多次調(diào)用等待函數(shù)而不會阻塞。這防止一個線程等待一個它已擁有的互斥對象時出現(xiàn)死鎖。不過,為了釋放所有權(quán),該線程必須為每一個等待操作調(diào)用一次ReleaseMutex函數(shù)。.3.3WaitForSingleObject函數(shù)功能:當如下情況之一發(fā)生時該函數(shù)返回:指定對象處于信號態(tài);超時。函數(shù)原型:DWORD WaitForSingleObject(HANDLEhHand1e,DWORDdwMilliseconds);參數(shù):hHandle:等待對象句柄。若想了解指定句柄的對象類型列表,參閱下面說明部分。在WndowsNT中,句柄必須有SYNCHRONIZE訪問權(quán)限。若想獲得更多的信息,請查看tandardAccessRights。dwMilliseconds:指定以毫秒為單位的超時間隔。如果超時,即使對象的狀態(tài)是非信號態(tài)的并且沒有完成,函數(shù)也返回。如果dwMilliseconds是0,函數(shù)測試對象的狀態(tài)并立刻返回:如果dwMil1seconds是INFINlTE,函數(shù)從不超時。返回值:如果函數(shù)調(diào)用成功,返回值表明引起函數(shù)返回的事件??赡苤等缦拢篧AIT—ABANDONED:指定對象是互斥對象,在線程被終止前,線程沒有釋放互斥對象?;コ鈱ο蟮乃鶎訇P(guān)系被授予調(diào)用線程,并且該互斥對象被置為非信號態(tài)。WAIT_OBJECT_0:指定對象的狀態(tài)被置為信號態(tài)。WAlT_TIMEOUT:超時,并且對象的狀態(tài)為非信號態(tài)。如果函數(shù)調(diào)用失敗,返回值是WAIT_FAILED。若想獲得更多錯誤信息,請調(diào)用GetLastError函數(shù)。4.3.4GetHead函數(shù)功能:用來獲取代表此列表中的頭元素的指針函數(shù)原型:CTypedPtrList::GetHead參數(shù):指定保存在列表中的元素類型的模板參數(shù)返回值:如果是通過一個指向constCTypedPtrList的指針訪問此列表,則GetHead返回一個類型由模板參數(shù)TYPE指定的指針。這使此函數(shù)只能被使用在賦值語句的右邊,這樣就保護了列表不被修改。a如果列表被直接訪問,或通過一個指向CTypedPtrList的指針訪問,則GetHead返回對一個類型由模板參數(shù)TYPE指定的指針的引用。這使得此函數(shù)可以使用在賦值語句的任何一邊,從而允許該列表可以被修改程序主要源碼清單由于代碼比較多,在此我給出生產(chǎn)者一消費者中核心部分調(diào)試好,可以運行的源碼,如果要完整代碼,請查看本程序原整的原代碼.//Mu1tiThreadD1g.cpp:implementationfile#include"stdafx.h"#include"MultiThread,h"include"Mu1tiThreadDlg.h"#include"afxtemp1.h"#include"afxmt.h"#include"time,h"#include"stdio.h"include"stdlib.h"#include"winbase.h"volatileintthreadController;volatileintcheck;volatileHANDLEhMutex;CListvCString,CString&>list;CListBox大pbox1,*pbox2,*pbox3,大pbox4,*pbox5;intnumber;ifdef_DEBUG#definenewDEBUG_NEW#undefTHIS_FILEstaticcharTHIS_FILE口=__FILE__;#endif///////////////////////////////////////////////////////////////////////////////classCObject;//CAboutDlgdialogusedforAppAboutclassCAboutDlg:publicCDialog//初始化消息句柄{public:CAboutDlg();enum{IDD=IDD_ABOUTBOX};oprotected:virtualvoidDoDataExchange(CDataExchange*pDX); //Implementationprotected:oDECLARE_MESSAGE_MAP()};voidCAboutDlg::DoDataExchange(CDataExchange*pDX){oCDialog::DoDataExchange(pDX);}BEGIN_MESSAGE_MAP(CAboutDlg,CDialog)END_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////CMultiThreadDlg::CMultiThreadDlg(CWnd*pParent/*=NULL*/):CDia1og(CMultiThreadDlg::IDD, pParent){om_hIcon=AfxGetApp()->LoadIcon(IDR_MAINFRAME);}voidCMultiThreadDlg::DoDataExchange(CDataExchange*pDX){CDialog::DoDataExchange(pDX);}BEGIN_MESSAGE_MAP(CMultiThreadDlg,CDialog)oON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_START,OnStart)oON_BN_CLICKED(IDC_STOP,OnStop)END_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////BOOLCMultiThreadDlg::OnInitDialog()//創(chuàng)建線程{oCDialog::OnInitDialog();*SERT((IDM_ABOUTBOX&0xFFF0)==IDM_ABOUTBOX);oASSERT(IDM_ABOUTBOX<0xF000);(Menu*pSysMenu=GetSystemMenu(FALSE);oif(pSysMenu!=NULL)o{oCStringstrAboutMenu;ostrAboutMenu.LoadString(IDS_ABOUTBOX);oif(!strAboutMenu.IsEmpty())o{opSysMenu->AppendMenu(MF_SEPARATOR);opSysMenu->AppendMenu(MF_STRING,IDM_ABOUTBOX,strAboutMenu);o}o}o//獲取對話框中子窗口控件的句柄pboxl=(CListBox*)GetDlgItem(IDC_LIST1);pbox2=(CListBox*)GetDlgItem(IDC_LIST2);pbox3=(CListBox*)GetDlgItem(IDC_LIST3);pbox4=(CListBox*)GetDlgItem(IDC_LIST4);opbox5=(CListBox*)GetDlgItem(IDC_LIST5);number=0;oreturnTRUE;//returnTRUE交出控制權(quán)}voidCMultiThreadDlg::OnSysCommand(UINTnID,LPARAMlParam)//獲取控制命令{if((nID&0xFFF0)==IDM_ABOUTBOX)o{ooCAboutDlgdlgAbout;o dIgAbout.DoModal();}eIseo{CDialog::OnSysCommand(nID,IParam);}}//窗體顯示大小voidCMultiThreadDlg::OnPaint(){if(IsIconic()){oCPaintDCdc(this);//devicecontextforpaintingoSendMessage(WM_ICONERASEBKGND,(WPARAM)dc.GetSafeHdc(),0);ointcxIcon=GetSystemMetrics(SM_CXICON);ointcyIcon=GetSystemMetrics(SM_CYICON);CRectrect;ooGetClientRect(&rect);oointx=(rect.Width()-cxIcon+1) /2;oointy=(rect.Height()—cyIcon+ 1)/2;odc.DrawIcon(x,y,m_hIcon);}elseo{ooCDialog::OnPaint();}}HCURSORCMultiThreadDlg::OnQueryDragIcon(){return(HCURSOR)m_hIcon;}voidCMultiThreadDlg::OnStart()〃開始創(chuàng)建線程{ohMutex=CreateMutex(NULL,FALSE,NULL);//初始化threadController=1;check=TRUE;oHWNDhWnd=GetSafeHwnd();//得到控制權(quán)。AfxBeginThread(ThreadProc,hWnd,THREAD_PRIORITY_NORMAL);//啟用生產(chǎn)者線程1(P1)AfxBeginThread(ThreadProc2,hWnd,THREAD_PRIORITY_NORMAL);//啟用生產(chǎn)者線程2(P2)AfxBeginThread(ThreadProc3,hWnd,THREAD_PRIORITY_NORMAL);//啟用生產(chǎn)者線程3(P3)^AfxBeginThread(Thread_consumer,hWnd,THREAD_PRIORITY_NORMAL);//啟用消費者線程1(S1)AfxBeginThread(Thread_consumer2,hWnd,THREAD_PRIORITY_NORMAL);〃啟用消費者線程2(S2)}voidCMultiThreadDlg::OnStop()//雙擊暫時停止所有工作{threadController=0;。check=FALSE;}UINTCMultiThreadDlg::ThreadProc(LPVOIDparam)//生產(chǎn)者1的生產(chǎn)過程{while(threadController){WaitForSingleObject(hMutex,INFINITE);//等待一個同步事件的到來if(number<20)srand((unsigned)time(NULL));//返回一個隨機數(shù)sointn;。 n=rand()%9+1;//隨機顯示字數(shù)Sleep(n*100);oCStringstr;gCStringstr—;for(inti=0;i<n;i++)//循環(huán)隨機的字數(shù)o{ostr_.Format("%c",65+rand()%9+l);//顯示大寫字母oostr.Insert(i,str_);//插入成一列}oolist.AddTail(CString(str));CStringstring;string.Format("%s%d%s%d”,"0xaa”,n,list.GetTail(),sizeof(list.GetTail())Asizeof(n));//按格式消息頭(1B,固定為0xaa),消息長度(1B),消息內(nèi)容(nB),校驗和(1B)o opbox1->AddString(string);〃打印onumber++;o}ooReleaseMutex(hMutex);〃釋放互斥o}oreturn 0;}UINTCMultiThreadDlg::ThreadProc2(LPVOIDparam){while(threadController)o{WaitForSingleObject(hMutex,INFINITE);oif(number<20)o{osrand((unsigned)time(NULL));oointn;ooon=rand()%9+1;ooSleep(n*10O);oCStringstr;oCStringstr_;oofor(inti=0;iVn; i++){

o str_.Format("%c”,97+rand()%9+1);oostr.Insert(i,str_);L1oolist.AddTail(CString(str));oooCStringstring;string.Format("%s%d%s%d”,"0xaa”,n,list.GetTai1(),sizeof(list.GetTail())Asizeof(n));opbox2->AddString(string);oo number++;o1oReleaseMutex(hMutex);1oreturn0;1UINTCMultiThreadDlg::ThreadProc3(LPVOIDparam){owhile(threadController)o{oWaitForSingleObject(hMutex,INFINITE);//等待一個同步事件的到來ooif(number<20)o{osrand((unsigned)time(NULL));〃返回一個隨機數(shù)o intn;on=rand()%9+l;o Sleep(n*l00);oCStringstr;ooCStringstr_;oofor(inti=0; i<n;i++)ooo{ooostr.Insert(i,str_);o1o str_.Format("%c",4ooostr.Insert(i,str_);o1o。list.AddTail(CString(str));眼CStringstring;string.Format("%s%d%s%d”,"0xaa”,n,list.GetTail(),sizeof(1ist.GetTail())Asizeof(n));g//1ist.AddHead(CString(string));pbox3->AddString(string);enumber++;“}“ReleaseMutex(hMutex);}return0;}U

溫馨提示

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

最新文檔

評論

0/150

提交評論