青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

一、    什么是進(jìn)程?什么是線程?
   進(jìn)程是一大堆系統(tǒng)對象擁有權(quán)的集合。如進(jìn)程擁有內(nèi)存上下 文,文件句柄,可以派生出很多線程,也可以擁有很多DLL模塊。在windows系統(tǒng)中,進(jìn)程并不完成實質(zhì)的工作,只是提供一個相對獨立的運行環(huán)境,線程 才是完成實際工作的載體。線程從屬于進(jìn)程,共享進(jìn)程所擁有的系統(tǒng)對象。線程是操作系統(tǒng)調(diào)度的單位。實質(zhì)上,線程就是一段可執(zhí)行代碼。
采用多進(jìn)程的優(yōu)點和缺點:
優(yōu)點:運行環(huán)境相對獨立,某一進(jìn)程的崩潰一般不會影響到其它進(jìn)程的執(zhí)行。
缺點:
耗時耗資源:啟動一個進(jìn)程需要申請大量的系統(tǒng)資源,其中包括虛擬內(nèi)存、文件句柄以及加載各種必要的動態(tài)鏈接庫;線程則不需要以上動作,因為它共享進(jìn)程中的所有資源。
“系統(tǒng)準(zhǔn)備一個進(jìn)程環(huán)境可能需要好幾M的空間”
通 信復(fù)雜:進(jìn)程的地址空間獨立,進(jìn)程A的地址X,在進(jìn)程B中可能是無意義的,這樣,當(dāng)進(jìn)程間需要共享數(shù)據(jù)時,就需要特殊的機制來完成這些工作。線程則在同一 地址空間,數(shù)據(jù)共享方便快捷。“線程是一個物美價廉的選擇,在一個Windows上擁有500個線程是一件很輕易的事情,但是500個進(jìn)程將是難以想象的 ”。

二、    為什么需要多線程(解釋何時考慮使用線程)
從用戶的角度考慮,就是為了得到更好的系統(tǒng)服務(wù);從程序自身的角度考慮,就是使目標(biāo)任務(wù)能夠盡可能快的完成,更有效的利用系統(tǒng)資源。綜合考慮,一般以下場合需要使用多線程:
1、    程序包含復(fù)雜的計算任務(wù)時
主要是利用多線程獲取更多的CPU時間(資源)。
2、    處理速度較慢的外圍設(shè)備
比如:打印時。再比如網(wǎng)絡(luò)程序,涉及數(shù)據(jù)包的收發(fā),時間因素不定。使用獨立的線程處理這些任務(wù),可使程序無需專門等待結(jié)果。
3、    程序設(shè)計自身的需要
WINDOWS系統(tǒng)是基于消息循環(huán)的搶占式多任務(wù)系統(tǒng),為使消息循環(huán)系統(tǒng)不至于阻塞,程序需要多個線程的來共同完成某些任務(wù)。
三、    使用多線程可能出現(xiàn)的問題(列舉問題)
事 實上,單純的使用線程不會產(chǎn)生任何問題,其啟動、運行和結(jié)束都是非常簡單的事情。在Win32環(huán)境下,啟動:CreateThread,運行就是函數(shù)執(zhí)行 的過程,中止就是函數(shù)返回的過程或者調(diào)用ExitThread。但是由于下列原因可能會使在使用線程的過程中帶來一系列問題:
1、    版本問題
多 任務(wù)的概念是隨著實際需求的提出而產(chǎn)生,最初的程序設(shè)計者并沒有考慮到代碼需要在多線程環(huán)境下運行,在多線程環(huán)境下使用這些代碼無疑將產(chǎn)生訪問沖突。最典 型的例子就是C runtime library。最早的C runtime library產(chǎn)生于20世紀(jì)70年代,當(dāng)時連多任務(wù)都是一個新奇的概念,更別說什么多線程了,該版本的庫中使用了大量全局變量和靜態(tài)變量(產(chǎn)生競爭條件 的根源,對局部變量無此要求,因為局部變量都使用棧,每個線程都有自己的棧空間,另外在啟動線程時,給線程函數(shù)的參數(shù)應(yīng)該是盡量使用值,而非指針或引用, 這樣可以避免因此帶來的沖突問題),如在該庫中統(tǒng)一使用一個errno變量來表明程序的錯誤碼,如果在多線程中使用該庫,并且都需要設(shè)置錯誤碼時,此時即 產(chǎn)生了一個沖突。
VC為防止以上問題,提供了另外一個線程安全的C runtime library,因此在寫多線程程序時,需要注意所連接庫的版本是否正確(該過程一般由應(yīng)用程序向?qū)瓿桑虼似綍r編程并無此問題)。與此有關(guān)的還有一些 其它版本:單線程版、多線程版調(diào)試版和多線程發(fā)行版。
2、    線程間共享資源時形成競爭條件(race condition)
一般而 言,線程并不是單獨行動,通常是多個線程分工協(xié)作,完成一個大任務(wù)中的不同小任務(wù),此時,這些線程之間就需要共同操作一些資源,比較典型的例子是多個線程 進(jìn)行文件操作或屏幕打印的情況:線程A在寫文件進(jìn)行了一半時,發(fā)生了context switch,另外一個線程B繼續(xù)進(jìn)行寫文件操作,此時文件的內(nèi)容將會凌亂不堪。甚至造成異常錯誤。典型的例子是,三個線程,線程A在堆中申請了一塊內(nèi)存 并填入了一個值,線程B讀取了該值后將該內(nèi)存釋放,如果線程C還要對該內(nèi)存操作時,將導(dǎo)致異常。
3、    線程間的通信問題
線程協(xié)作完 成某一任務(wù)時,有時還需要通信以控制任務(wù)的執(zhí)行步驟,典型的例子就是讀寫者線程:寫線程在對某內(nèi)存區(qū)域?qū)懲陻?shù)據(jù)后,需要通知讀線程來取,讀完之后又需要通 知寫線程可以繼續(xù)往里寫入數(shù)據(jù)。更為廣泛的例子是:某線程需要等待某一事件發(fā)生,以決定是否繼續(xù)工作。此時,如果沒有正確控制線程的執(zhí)行過程,將導(dǎo)致不可 預(yù)料的錯誤發(fā)生。
4、    由于不規(guī)范的使用線程導(dǎo)致系統(tǒng)效率下降
進(jìn)程中包含了一個以上的線程,這些線程可能會動態(tài)的申請某些資源,如 某些數(shù)據(jù)庫線程可能會動態(tài)加載數(shù)據(jù)庫方面的動態(tài)鏈接庫,但是在該線程結(jié)束時,并沒有及時釋放該動態(tài)鏈接庫即被其他線程強行終止,于是該進(jìn)程中的該動態(tài)鏈接 庫引用計數(shù)不為0,從而導(dǎo)致該動態(tài)鏈接庫在該進(jìn)程中存有一個副本。當(dāng)這種情況頻繁時,將對系統(tǒng)效率產(chǎn)生很大的影響。
四、    線程的類型(解釋UI線程和WORKER線程的區(qū)別和聯(lián)系)
嚴(yán)格說來,線程并沒有什么本質(zhì)區(qū)別,但是Win32編程文檔中卻反復(fù)強調(diào)UI線程和Worker線程的區(qū)別。并給出了它們的定義:
UI線程就是:擁有消息隊列和窗口的線程,并且它的主要職責(zé)是處理窗口消息。Worker線程則沒有消息隊列,但是當(dāng)Worker線程產(chǎn)生一個用戶界面(消息框和模式對話框除外)時,則該線程則搖身一變,成為UI線程。
問題:
1、    線程的消息隊列和窗口的消息隊列
在Win32中,每個線程都有它自己專屬的消息隊列,而窗口并不總是有消息隊列,因為一個UI線程可以創(chuàng)建很多個窗口。
2、    UI線程到底跟Worker線程存在什么差別?
職 責(zé)不一樣:UI線程負(fù)責(zé)處理與用戶界面有關(guān)的消息,一般而言,用戶界面消息來自用戶輸入(如鼠標(biāo)鍵盤消息)、系統(tǒng)消息(如WM_PAINT)以及程序產(chǎn)生 的用戶自定義消息。因此,在該線程下一般不能存在等待(wait…)函數(shù),這樣該線程就會掛起,從而影響消息隊列的處理。Worker線程不用處理用戶界 面消息,而是完成一般性的計算任務(wù),該線程等待計算過程中必要的資源時,不會影響到界面的刷新動作。
操作系統(tǒng)的管理不一樣:對UI線程來說,產(chǎn)生一個UI線程實際上產(chǎn)生了兩個線程,一個是其自身,另一個是操作系統(tǒng)為響應(yīng)其GDI調(diào)用而產(chǎn)生的影子線程。
3、    Worker線程變成UI線程有什么不好?
Worker線程一般用于計算,此時如果它轉(zhuǎn)換為UI線程的話,將無暇顧及用戶界面的消息響應(yīng)。
4、    Worker線程可否擁有自己的消息隊列?
Worker線程同樣可以擁有自己的消息隊列,該隊列一般通過PeekMessage()調(diào)用建立,通過GetMessage調(diào)用來解析。(具體實現(xiàn)看源碼)
5、    用以下規(guī)則來管理win32中線程、消息和窗口的互動
所有傳送給某一窗口的消息,將由產(chǎn)生該窗口的線程負(fù)責(zé)處理。
五、    線程的啟動和中止(解釋啟動線程的不同方式及其它們的區(qū)別和實用場合)
隨C Runtime Library庫的更新和編程環(huán)境的不同,線程的啟動方式也有所不同,以下介紹幾種典型的線程啟動方式。
1、_beginthread和_endthread
該 函數(shù)是C Runtime Library中的函數(shù),它負(fù)責(zé)初始化函數(shù)庫;其原型如下unsigned long _beginthread( void( __cdecl *start_address )( void * ), unsigned stack_size, void *arglist );“該函數(shù)被認(rèn)為是頭腦簡單的函數(shù)”,使用該函數(shù)導(dǎo)致無法有效的控制被創(chuàng)建線程,如不能在啟動時將該線程掛起,無法為該線程設(shè)置優(yōu)先權(quán)等。另外,該函數(shù) 為隱藏Win32的實現(xiàn)細(xì)節(jié),啟動線程的第一件事情即將自己的Handle關(guān)閉,因此也就無法利用這個Handle來等待該線程結(jié)束等操作。該函數(shù)是早期 的C Runtime Library的產(chǎn)物,不提倡使用,后期的改良版本為_beginthreadex。
通過_beginthread啟動的線程在應(yīng)當(dāng)通過調(diào)用_endthread結(jié)束,以保證清除與線程相關(guān)的資源。
2、_beginthreadex和_endthreadex
該 函數(shù)是C Runtime Library中的一個函數(shù),用標(biāo)準(zhǔn)C實現(xiàn),相比_beginthread,_beginthreadex對線程控制更為有力(比前者多三個參數(shù)),是 _beginthread的加強版。其原型為unsigned long _beginthreadex( void *security, unsigned stack_size, unsigned ( __stdcall *start_address )( void * ), void *arglist, unsigned initflag, unsigned *thrdaddr );該函數(shù)返回新線程的句柄,通過該句柄可實現(xiàn)對線程的控制。雖然,該函數(shù)是用標(biāo)準(zhǔn)C寫的(即可不加修改就可以移植到其他系統(tǒng)執(zhí)行),但是由于它與 Windows系統(tǒng)有著緊密的聯(lián)系(需要手動關(guān)閉該線程產(chǎn)生的Handle),因此實現(xiàn)時,往往需要包含windows.h。
通過_beginthreadex啟動的線程通過調(diào)用_endthreadex做相關(guān)清理。
3、CreateThread和ExitThread
CreateThread 是Win32 API函數(shù)集中的一個函數(shù),其原型為HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,DWORD dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD wCreationFlags,LPDWORD lpThreadId);該函數(shù)使用Win32編程環(huán)境中的類型約定,只適用于Windows系統(tǒng)。參數(shù)形式與_beginthreadex一致,對線程 控制能力也與之一致,只是該函數(shù)與C Runtime Library沒有任何關(guān)系,它不負(fù)責(zé)初始化該庫,因此在多線程環(huán)境中,如果使用該函數(shù)啟動線程,則不應(yīng)使用C Runtime Library中的多線程版本的函數(shù)。取而代之的應(yīng)該是功能相對應(yīng)的 Win32 API函數(shù);另外,應(yīng)當(dāng)自己手工提供線程同步的代碼。
通過CreateThread創(chuàng)建的線程則通過ExitThread做清理工作。
4、AfxBeginThread和AfxEndThread
AfxBeginThread 是MFC提供的線程啟動方式,它是個重載函數(shù),有兩種調(diào)用形式:Worker線程版和UI線程版。MFC對Win32線程做了小心的很好的封裝 (CWinThread),雖然其總是調(diào)用了_beginthreadex來啟動一個線程,但是其額外做的工作使得在MFC環(huán)境下,操作線程變得簡單明 了,并且不需要太多的關(guān)注細(xì)節(jié)問題。MFC在線程的封裝方面主要做了下列事情:
1、    自動清除CWinThread對象
2、    關(guān)閉線程handle,線程對象自動釋放
3、    存儲了線程相關(guān)的重要參數(shù),即線程handle和線程ID
4、    輔之以其它MFC同步對象,方便的實現(xiàn)線程同步
5、    使用了嚴(yán)格的斷言調(diào)試語句,使線程調(diào)試變得相對簡單

“(C Runtime Library是用標(biāo)準(zhǔn)C開發(fā)的實用函數(shù)集)如果多線程程序中使用了標(biāo)準(zhǔn)C庫函數(shù),并用CreateThread()和ExitThread(),則會導(dǎo) 致內(nèi)存泄漏。解決這個問題的方法是用C運行庫(run-time library)函數(shù)來啟動和終止線程,而不用WIN32 API定義的CreateThread()和ExitThread()。在C運行庫函數(shù)中,它們的替代函數(shù)分別是_beginthreadex()和 _exitthreadex(),需要的頭文件是_process.h。在VC6.0下,還需在 Project->Settings->C/C++->Code Generation中選擇Multithreaded Runtime Library。當(dāng)然,也可以通過避免使用C標(biāo)準(zhǔn)庫函數(shù)的方法來解決上述問題,WIN32提供了一些C標(biāo)準(zhǔn)庫函數(shù)的替代函數(shù),例如,可用 wsprintf()和lstrlen()來代替sprintf()和strlen()。這樣,使用CreateThread()和 ExitThread()不會出現(xiàn)問題。”
六、    線程的同步問題(介紹Windows的同步機制)
1、    怎樣等待一個線程結(jié)束(忙等(busy loop)和高效的等(WaitForSingleObject))
1)    忙等(busy loop)
hThrd = CreateThread(NULL,0,ThreadFunc,(LPVOID)1,0,&threadId );
for (;;)
{
GetExitCodeThread(hThrd, &exitCode);
if ( exitCode != STILL_ACTIVE )
break;
}
CloseHandle(hThrd);
缺點:耗費CPU資源,且如果在UI線程中這樣等待將導(dǎo)致窗口無法刷新。不推薦使用。
2)    高效的等待
(1)WaitForSingleObject;
關(guān)于WaitForSingleObject的參數(shù),前者為等待的對象,后者為等待的時間,對某些執(zhí)行時間較長的線程,可以設(shè)置一個合適的值,等待完這個時間后,更新界面,然后繼續(xù)等待,或者強行終止線程。
將以上的等待部分的代碼改為:
WaitForSingleObject(hThrd,INFINITE);
該函數(shù)相當(dāng)于Sleep函數(shù),當(dāng)需要等待的對象(句柄)沒有被觸發(fā)時,等待的線程將被自動掛起。該方法解決了耗費CPU時間的問題,但是在UI線程中,仍不能使用該方法來等待某一線程結(jié)束。
解決方法之一:創(chuàng)建一個Worker管理者線程,在該線程中等待,工作者線程完成,然后由管理者線程發(fā)消息通知UI線程更新窗口。
(2)WaitForMultipleObject
該函數(shù)允許在同一時間等待多個對象,函數(shù)的原型如下:
DWORD WaitForMultipleObject(DWORD nCount,CONST HANDE *lpHandles,BOOL bWaitAll,dwMilliseconds);
第一個參數(shù)表示句柄數(shù)組的大小;等待的對象不能超過64
第二個參數(shù)為句柄數(shù)組;
第三個參數(shù)表明是否等待所有對象激發(fā)。True表示是。
第四個參數(shù)為等待時間。
關(guān)于WaitForMultipleObject的返回值:
當(dāng)bWaitAll為True時,返回值為WAIT_OBJECT_0;
當(dāng)bWaitAll為false時,返回值減去WAIT_OBJECT_0,就是激發(fā)對象所在的下標(biāo)。
應(yīng)用:
A)    解決多個工人n完成多個任務(wù)m(n<m)的問題(bWaitAll設(shè)置為false)
解決的思路如下:先從m個任務(wù)中取出n個任務(wù),對應(yīng)地用n個工人去完成,然后利用該函數(shù)等待其中任意一個工人結(jié)束任務(wù),一旦結(jié)束則讓其做另外一個任務(wù)
B)    解決等待多個資源的問題(bWaitAll設(shè)置為true)
哲學(xué)家就餐問題:5個哲學(xué)家在圓桌旁,每個哲學(xué)家左手邊放著1只筷子,哲學(xué)家做兩件事情,吃飯和思考,吃飯時同時需要其左右的兩只筷子。
解決思路:將哲學(xué)家模擬為線程,筷子為資源,只有哲學(xué)家線程同時獲得兩個資源時,方可進(jìn)一步動作(吃飯)。即:
WaitForMultipleObjects(2, myChopsticks, TRUE, INFINITE);
MyChopsticks是一個大小為5的核心對象數(shù)組。
        (3)MsgWaitForMultipleObjects
        原型:
DWORD MsgWaitForMultipleObjects( DWORD nCount,CONST HANDLE pHandles,BOOL fWaitAll,DWORD dwMilliseconds,DWORD dwWakeMask);
    前 幾個參數(shù)含義同WaitForMultipleObject,最后一個是消息屏蔽標(biāo)識,指示接收消息的類型。此外返回值也有額外的意義:當(dāng)消息到達(dá)時,該 函數(shù)返回WAIT_OBJECT_0+nCount。以下是常見的使用MsgWaitForMultipleObjects的架構(gòu):
  while (!quit)
    {   // Wait for next message or object being signaled
        DWORD   dwWake;
        dwWake = MsgWaitForMultipleObjects(
                                gNumPrinting,
                                gPrintJobs,
                                FALSE,
                                INFINITE,
                                QS_ALLEVENTS);

        if (dwWake >= WAIT_OBJECT_0 && dwWake < WAIT_OBJECT_0 + gNumPrinting)
        {  
            //對象被觸發(fā)
        } // end if
        else if (dwWake == WAIT_OBJECT_0 + gNumPrinting)
        {
            //有消息到達(dá)
            while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
            {   // Get Next message in queue
                 if (msg.message == WM_QUIT)
                 {
                     quit = TRUE;
                     exitCode = msg.wParam;
                     break;
                 } // end if
                 TranslateMessage(&msg);
                 DispatchMessage(&msg);
           } // end while
        }
    } // end while
2、    怎樣有效的控制一個線程
在任何情況下,切記線程的核心屬性為:線程的句柄,線程的ID號。因此控制一個線程也需從這兩方面著手。
1)    使用能返回線程Handle的啟動函數(shù)來啟動線程(除_beginthread外)
2)    盡量不要使一個工作量較大的線程成為“悶葫蘆”,從而使該線程能夠接收外界通知消息;如下列代碼:


MSG msg;
    while(1)
    {
        PeekMessage(&msg,NULL,0,0,PM_REMOVE);
        if(msg.message==WM_MY)
            break;
        Sleep(100);
    }
注:GetMessage也是用來得到消息隊列中一條消息的函數(shù),它們的區(qū)別在于GetMessage是同步的,即如果消息隊列中沒有消息的話,該線程將自動掛起。使用GetMessage可以使Worker線程成為一個一步一動的線程!
    MSG msg;
    while(GetMessage(&msg,NULL,0,0))
    {
        if(msg.message==WM_MY)
        {
            //Do something here
}
    }
以上的過程也可以通過事件對象予以實現(xiàn)。
懸而未決的問題:怎么控制一個正在等待其他事件的線程。如:一個TCP監(jiān)聽線程,在某一Socket上listen,此時該線程處于掛起狀態(tài)!但是現(xiàn)在主線程又需要關(guān)閉該線程,應(yīng)該怎么操作!

3、    怎樣互斥訪問一個資源(CMutex和Critical Section)
何時需要一個互斥對象?
常 見的情形:多個線程需要不定時的操作同一鏈表(鎖鏈表的頭指針);多個線程需要不定時的進(jìn)行寫文件或是進(jìn)行屏幕輸出(鎖文件句柄或屏幕句柄);多個線程需 要不定時對某個計數(shù)器進(jìn)行操作(鎖這個變量);在多線程環(huán)境嚇,凡是涉及到對全局變量、靜態(tài)變量、堆中的內(nèi)存進(jìn)行訪問時,都應(yīng)該考慮,是否可能出現(xiàn)一個 race condition(競爭條件)。
1)    互斥器
Win32提供了對互斥資源訪問的一整套機制,其中之一就是互斥器,MFC將這些API函數(shù)加以封裝,形成了CMutex互斥類,使用這兩種方法都能夠?qū)崿F(xiàn)對資源的互斥訪問。
Win32中的API:
CreateMutex:
原型:
HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,   BOOL bInitialOwner,  LPCTSTR lpName );
第一個參數(shù)為安全屬性;
第二個參數(shù)用來指示互斥器的擁有者是否為當(dāng)前線程;
第三個參數(shù)為互斥器的名稱;
當(dāng)不再需要互斥器時,應(yīng)當(dāng)調(diào)用CloseHandle關(guān)閉。
約 定:互斥器產(chǎn)生之后,由某一線程完成鎖定工作(即調(diào)用Wait…函數(shù)),此時系統(tǒng)將該mutex的擁有權(quán)交于該線程,然后短暫地將該對象設(shè)置為激發(fā)態(tài),于 是Wait…函數(shù)返回,做完相應(yīng)的工作之后(如:修改鏈表指針、修改計數(shù)器、寫文件等),調(diào)用ReleaseMutex釋放擁有權(quán)。周而復(fù)始。
MFC中的互斥器CMutex對象:
A、    利用其構(gòu)造函數(shù)產(chǎn)生一個互斥器對象
HANDLE CreateMutex( LPSECURITY_ATTRIBUTES lpMutexAttributes,BOOL bInitialOwner, LPCTSTR lpName);
B、    配合CSingleLock或者CmutipleLock產(chǎn)生一個臨時對象,對產(chǎn)生的互斥器進(jìn)行加鎖和釋放的動作;
2)    臨界區(qū)
另一個提供互斥訪問的機制是Critical Section,該機制較前一種方法廉價,因為它不屬于不是系統(tǒng)的核心對象;臨界區(qū)可以反復(fù)進(jìn)入,這一點與Mutex有所區(qū)別,這需要我們在使用臨界區(qū)時,保證進(jìn)入的次數(shù)要等于離開的次數(shù)。
相關(guān)函數(shù)為InitializeCriticalSection、DeleteCriticalSection、EnterCriticalSection、LeaveCriticalSection。
4、    怎樣等待多個不同(或者相同)資源(WaitForMultiObject)
等待多個不同資源在多線程程序設(shè)計中時常遇到,如:等待某一線程結(jié)束和某一個資源被釋放,等待緩沖區(qū)和設(shè)備準(zhǔn)備好兩個資源;這種現(xiàn)實情況,可以分別為不同的資源設(shè)置系統(tǒng)對象,然后利用WaitForMultiObject進(jìn)行等待。
5、    怎樣等待多個資源中的一個(使用CSemaphore)
現(xiàn)實中還可能出現(xiàn)如下情形:客人租相機的問題:有若干客人需要,租相機,總相機數(shù)為n,相機租完后,客人必須等待,只要有一個相機,則某客人就可以等到租借。還有許多問題可以用這種Producer/consumer模型加以概括。
這種情形即是等待多個資源中的一個的情況,在Win32程序設(shè)計中則經(jīng)常使用信號量(Semaphore)來解決此問題。
Win32系統(tǒng)中,信號量具有以下特性:
一 個信號量可以被鎖定N次,N一般代表可用資源的個數(shù),上例中即可代表相機的個數(shù),信號量初始化后,在Win32環(huán)境下調(diào)用一次Wait…操作即表示對其的 一次鎖定,信號量的值相應(yīng)加1,操作完后,調(diào)用ReleaseSemaphore操作,即代表資源釋放(上述例子中就是歸還相機)。MFC對Win32信 號量的相關(guān)API函數(shù)進(jìn)行了封裝(CSemaphore),配合CMultiLock 或者 CSingleLock即可實現(xiàn)鎖定和資源釋放的動作。
七、    線程間的通信
線程間的通信有許多方法可以實現(xiàn),視場合不同也有不同的應(yīng)用,大致可以分為兩類:進(jìn)程內(nèi)的線程通信和進(jìn)程間的通信。關(guān)于進(jìn)程內(nèi)線程的通信,前面所述的各種同步互斥等待機制也可歸屬線程間通信的范疇,
1、    使用線程消息實現(xiàn)線程通信
2、    使用事件對象實現(xiàn)線程通信
Win32還提供了一種比較靈活的核心對象,該對象完全受控于程序(只是清除的時候由系統(tǒng)回收),這就是Event(事件)對象。事件對象一般用于線程間的通知。下面先看事件對象的一些屬性:
創(chuàng)建一個事件對象可以調(diào)用Win32 API函數(shù)完成,也可以使用MFC封裝的事件對象。其API原型為:
HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,BOOL bManualReset,BOOL bInitialState, LPCTSTR lpName );
第二個參數(shù)指示事件對象是否為手動修改狀態(tài)(手動修改需要顯式調(diào)用ResEvent函數(shù));第三個參數(shù)設(shè)置事件對象的初態(tài),true為激發(fā)態(tài),false為非激發(fā)態(tài)。第四個參數(shù)為事件的名字。
事件對象自從創(chuàng)建后即在程序的控制下處于激發(fā)態(tài)和非激發(fā)態(tài)之間翻轉(zhuǎn)。
八、    線程代碼的調(diào)試
九、    什么是線程安全的代碼
十、    多線程程序設(shè)計的幾個原則

posts - 94, comments - 138, trackbacks - 0, articles - 94

Copyright © RichardHe

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美成人性生活| 欧美中文在线免费| 亚洲一级一区| 日韩特黄影片| av成人福利| 亚洲精品视频免费在线观看| **性色生活片久久毛片| 亚洲第一区色| 亚洲精品孕妇| 亚洲视频网站在线观看| 欧美在线综合视频| 久久综合九色综合欧美狠狠| 免费亚洲网站| 亚洲精品国产精品乱码不99按摩| 亚洲欧洲一区二区三区在线观看 | 亚洲欧美日韩天堂| 香蕉成人久久| 欧美高清在线一区| 99在线|亚洲一区二区| 亚洲欧美视频一区| 六十路精品视频| 欧美三级视频在线| 国产在线精品自拍| 99re热这里只有精品免费视频| 亚洲综合精品| 欧美高清在线观看| 亚洲自拍偷拍一区| 美日韩在线观看| 国产精品久久7| 一区二区三区在线免费观看| 亚洲视频每日更新| 欧美成人国产va精品日本一级| 亚洲美女视频| 久久免费99精品久久久久久| 国产精品r级在线| 亚洲国产婷婷香蕉久久久久久99| 午夜精品久久一牛影视| 亚洲精品极品| 美女黄毛**国产精品啪啪| 国产精品嫩草影院av蜜臀| 亚洲欧洲一区二区三区| 玖玖在线精品| 亚洲综合大片69999| 欧美日韩国产精品一卡| 亚洲福利免费| 久久九九国产精品| 国产精品99久久久久久久久| 欧美裸体一区二区三区| 小处雏高清一区二区三区| 欧美黄色视屏| 亚洲高清视频在线观看| 久久国产一区二区三区| 亚洲无线一线二线三线区别av| 欧美gay视频| 尤物精品国产第一福利三区 | 亚洲激情欧美激情| 久久美女性网| 亚洲欧美在线网| 欧美三级网址| 一区二区日本视频| 亚洲日韩欧美视频| 欧美激情一区| 一本色道久久88综合日韩精品| 欧美高清不卡| 久久婷婷色综合| 1000部国产精品成人观看| 毛片一区二区| 老司机67194精品线观看| 在线免费观看日本一区| 欧美77777| 欧美高清不卡| 一区二区三区黄色| 亚洲图片在线观看| 国产精品影音先锋| 欧美伊人影院| 久久久亚洲欧洲日产国码αv | 欧美精品三区| 一本一道久久综合狠狠老精东影业 | 久久精品国产第一区二区三区最新章节 | 亚洲国产精品久久人人爱蜜臀| 欧美.www| 亚洲视频网站在线观看| 亚洲自拍三区| 一区二区三区中文在线观看| 欧美激情麻豆| 欧美日本国产精品| 欧美一区二区三区免费在线看 | 欧美日韩视频免费播放| 欧美亚洲日本国产| 久久久久久亚洲精品不卡4k岛国| 在线电影一区| 日韩视频一区二区三区| 国产一区二区三区精品欧美日韩一区二区三区 | 亚洲第一区在线观看| 亚洲国产精品视频一区| 欧美视频三区在线播放| 久久国产精品亚洲va麻豆| 久久精品女人| 宅男精品视频| 欧美中文在线字幕| 99国产精品私拍| 久久成年人视频| 日韩天堂在线观看| 久久精品欧美日韩| 亚洲一二三区在线| 蜜臀a∨国产成人精品 | 亚洲男人第一网站| 久久视频一区| 亚洲欧美日本精品| 欧美sm视频| 久久综合九色| 国产美女精品| 一本大道av伊人久久综合| 国内精品久久久久影院色| 亚洲免费久久| 亚洲精品亚洲人成人网| 久久久久国产精品一区三寸| 午夜精品久久久久久久久久久久久| 牛人盗摄一区二区三区视频| 久久久国产精品一区二区中文 | 久久国产精品99国产| 亚洲午夜一区二区| 欧美va亚洲va国产综合| 久久综合九色综合欧美就去吻 | 国产日产欧产精品推荐色| 夜夜嗨av色综合久久久综合网| 91久久精品一区| 久久精品噜噜噜成人av农村| 欧美一级免费视频| 国产精品久久激情| 亚洲午夜激情网站| 亚洲欧美一区二区三区极速播放| 欧美日韩一区综合| 99re6这里只有精品视频在线观看| 最新国产拍偷乱拍精品 | 乱码第一页成人| 米奇777超碰欧美日韩亚洲| 国产一区二区日韩精品欧美精品| 亚洲欧美日韩一区| 久久精品国产第一区二区三区| 国产精品一区=区| 亚洲一级免费视频| 欧美一区二区三区四区夜夜大片| 国产精品成人一区二区三区夜夜夜| 亚洲精品久久久久久下一站| a91a精品视频在线观看| 欧美日韩国产一中文字不卡| 99精品久久久| 欧美在线地址| 很黄很黄激情成人| 久久久久久久综合| 欧美高清不卡| 亚洲少妇自拍| 国产精品捆绑调教| 欧美在线视频日韩| 99精品黄色片免费大全| 欧美日韩国产小视频在线观看| 一区二区三区偷拍| 久久久久久免费| 亚洲黄色在线| 欧美午夜视频在线| 欧美一区精品| 亚洲第一区在线| 亚洲一区999| 国产一区日韩一区| 免费不卡在线观看| 亚洲午夜在线| 男女精品视频| 亚洲午夜视频| 狠狠干成人综合网| 久久免费高清| 亚洲免费久久| 蜜桃久久av一区| 亚洲精品免费一区二区三区| 欧美视频中文字幕在线| 久久精品国产亚洲高清剧情介绍 | 午夜精品久久久久久99热| 国产一区激情| 免费日韩av电影| 亚洲一区二区三区成人在线视频精品 | 中文精品在线| 精品成人免费| 欧美激情欧美狂野欧美精品| 亚洲少妇最新在线视频| 久久亚洲国产精品日日av夜夜| 亚洲精品久久久久久一区二区| 欧美亚日韩国产aⅴ精品中极品| 中文国产一区| 免费在线日韩av| 欧美伊人久久| 亚洲婷婷在线| 亚洲国产专区| 国产三级精品三级| 欧美国产欧美亚州国产日韩mv天天看完整| 亚洲欧美成人在线| 亚洲精品1区2区| 麻豆久久精品| 香蕉久久夜色精品国产使用方法| 亚洲欧洲日本专区| 在线观看视频一区二区欧美日韩|