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

大龍的博客

常用鏈接

統(tǒng)計(jì)

最新評(píng)論

Windows線程函數(shù)概述 - 《C++編程藝術(shù)》

Windows提供了多組支持多線程的應(yīng)用程序接口(API)函數(shù)。許多讀者已經(jīng)對(duì)Windows提供的多線程函數(shù)有一定程度的了解,但是對(duì)于那些不熟悉這些的讀者,本章提供了這些函數(shù)的概述。記住,Windows提供了許多其他的基于多線程的函數(shù),這些函數(shù)需要您自己去探索。

為了使用Windows的多線程函數(shù),必須在程序中包含<Windows.h>。

3.4.1 線程的創(chuàng)建和終止

Windows API提供了CreateThread()函數(shù)來(lái)創(chuàng)建一個(gè)線程。其原型如下所示:

HANDLE CreateThread(LPSECURITY_ATTRIBUTES secAttr,

SIZE_T stackSize,

LPTHREAD_START_ROUTINE threadFunc,

LPVOID param,

DWORD flags,

LPDWORD threadID);

在此,secAttr是一個(gè)用來(lái)描述線程的安全屬性的指針。如果secAttr是NULL,就會(huì)使用默認(rèn)的安全描述符。

每個(gè)線程都具有自己的堆棧。可以使用stackSize參數(shù)來(lái)按字節(jié)指定新線程堆棧的大小。如果這個(gè)整數(shù)值為0,那么這個(gè)線程堆棧的大小與創(chuàng)建它的線程相同。如果需要的話,這個(gè)堆棧可以擴(kuò)展。(通常使用0來(lái)指定線程堆棧的大小)。

每個(gè)線程都在創(chuàng)建它的進(jìn)程中通過(guò)調(diào)用線程函數(shù)來(lái)開(kāi)始執(zhí)行。線程的執(zhí)行一直持續(xù)到線程函數(shù)返回。這個(gè)函數(shù)的地址(也就是線程的入口點(diǎn))在threadFunc中指定。每個(gè)線程函數(shù)都必須具有這樣的原型:

DWORD WINAPI threadfunc(LPVOID param);

需要傳遞給新線程的任何參數(shù)都在CreateThread()的param中指定。線程函數(shù)在它的參數(shù)中接收這個(gè)32位的值。這個(gè)參數(shù)可以用作任何目的。函數(shù)返回它的退出狀態(tài)。

參數(shù)flags確定了線程的執(zhí)行狀態(tài)。如果它是0,線程會(huì)立即執(zhí)行。如果是CREATE_SUSPEND,線程則以掛起狀態(tài)創(chuàng)建并等待執(zhí)行。(可以通過(guò)調(diào)用ResumeThread()來(lái)開(kāi)始執(zhí)行,稍后討論)。

與線程相關(guān)的標(biāo)識(shí)符以threadID所指向的長(zhǎng)整型返回。

如果成功,函數(shù)則向線程返回一個(gè)句柄。如果失敗,則返回NULL。可以通過(guò)調(diào)用CloseHandle()來(lái)顯式銷毀這個(gè)線程。否則,會(huì)在父進(jìn)程結(jié)束時(shí)自動(dòng)銷毀它。

如前所述,當(dāng)線程的入口函數(shù)返回時(shí)終止執(zhí)行線程。進(jìn)程也可以使用TerminateThread()或者ExitThread()來(lái)手動(dòng)終止線程,這兩個(gè)函數(shù)的原型如下:

BOOL TerminateThread(HANDLE thread, DWORD status);

VOID ExitThread(DWORD status);

對(duì)于TerminateThread(),thread是將要終止的線程的句柄。ExitThread()只能用來(lái)終止調(diào)用了ExitThread()的線程。對(duì)于兩個(gè)函數(shù)而言,status是終止?fàn)顟B(tài)。TerminateThread()如果成功,則會(huì)返回非0值,否則返回0。

調(diào)用ExitThread()在功能上等價(jià)于允許線程函數(shù)正常返回。這意味著堆棧會(huì)正確地重新設(shè)置。當(dāng)使用TerminateThread()結(jié)束線程時(shí),線程會(huì)立刻終止,而會(huì)執(zhí)行任何特定的清理任務(wù)。另外,TerminateThread()可能會(huì)停止正在執(zhí)行重要操作的線程。為此,當(dāng)入口函數(shù)返回時(shí),通常最好(也是最容易的)讓線程正常終止。

3.4.2 Visual C++對(duì)CreateThread()和ExitThread()的替換

盡管CreateThread()和ExitThread()是用來(lái)創(chuàng)建并終止線程的Windows API函數(shù),我們?cè)诒菊虏⒉粫?huì)使用它們。原因是在Visual C++中(其他的Windows兼容的編譯器也可能有這個(gè)問(wèn)題)使用這兩個(gè)函數(shù)時(shí),會(huì)導(dǎo)致內(nèi)存泄漏,丟失少量的內(nèi)存。對(duì)于Visual C++,如果多線程程序利用了C/C++標(biāo)準(zhǔn)庫(kù)函數(shù)并使用了CreateThread()和ExitThread(),就會(huì)丟失少量的內(nèi)存。(如果您的程序沒(méi)有使用C/C++的標(biāo)準(zhǔn)庫(kù),就不會(huì)發(fā)生這樣的內(nèi)存丟失)。為了避免這種情況,必須使用Visual C++運(yùn)行庫(kù)中定義的函數(shù)來(lái)開(kāi)始和終止線程,而不是使用由Win32 API指定的函數(shù)。這些函數(shù)類似于CreateThread()和ExitThread(),但是不會(huì)產(chǎn)生內(nèi)存泄漏。

提示:

如果使用非Visual C++的編譯器,如果需要的話,檢查它的文檔來(lái)確定是否需要忽略CreateThread()和ExitThread(),以及如何做到這一點(diǎn)。

Visual C++用_beginthreadex()和_endthreadex()來(lái)取代CreateThread()和ExitThread()。這兩個(gè)函數(shù)都需要頭文件<process.h>。下面是_beginthreadex()函數(shù)的原型:

uintptr_t _beginthreadex(void *secAttr, unsigned stackSize,

unsigned (__stdcall *threadFunc)(void *),

void *param, unsigned flags,

unsigned *threadID);

正如您看到的那樣,_beginthreadex()的參數(shù)類似于CreateThread()的參數(shù)。另外,這些參數(shù)與CreateThread()指定的參數(shù)有相同的含義。secAttr是一個(gè)用來(lái)描述線程安全性屬性的指針。然而,如果secAttr為NULL,則會(huì)使用默認(rèn)的安全描述符。新線程堆棧的大小由stackSize參數(shù)按字節(jié)數(shù)傳遞。如果這個(gè)值為0,那么這個(gè)線程堆棧的大小與進(jìn)程中創(chuàng)建它的主線程的大小相同。

線程函數(shù)的地址(也就是線程的入口點(diǎn))在threadFunc中指定。對(duì)于_beginthreadex(),線程函數(shù)的原型如下:

unsigned_stdcall threadfunc(void *param)

這個(gè)原型在功能上等價(jià)于CreateThread()的線程函數(shù)的原型,但是它使用了不同的類型名稱。想要傳遞給新線程的任何參數(shù)都在param參數(shù)中指定。

flags參數(shù)確定線程的執(zhí)行狀態(tài)。如果flags參數(shù)為0,線程會(huì)立即開(kāi)始執(zhí)行。如果flags參數(shù)為CREATE_SUSPEND,則以掛起狀態(tài)創(chuàng)建線程。(可以調(diào)用ResumeThread()來(lái)開(kāi)始它)。與線程相關(guān)的標(biāo)識(shí)符以threadID指向的double word返回。

如果成功,則這個(gè)函數(shù)返回一個(gè)線程的句柄;如果失敗,則返回0。類型uintptr_t指定了可以擁有指針或者句柄的Visual C++類型。

_endthreadex()的原型如下:

void _endthreadex(unsigned status);

它的功能就像ExitThread()那樣,停止線程并返回status中指定的退出代碼(exit code)。

由于Windows下使用最廣泛的編譯器是Visual C++,因此本章示例將使用_beginthreadex()和_endthreadex()而不是使用它們的等價(jià)的API函數(shù)。如果您使用了非Visual C++的編譯器,那么只需要用CreateThread()和EndThread()來(lái)替代這兩個(gè)函數(shù)。

當(dāng)使用_beginthreadex()和_endthreadex()時(shí),必須記住鏈接多線程庫(kù)。這隨編譯器的不同而不同。在此有一些示例。當(dāng)使用Visual C++的命令行編譯器時(shí),包括-MT選項(xiàng)。為了在Visual C++ 6 IDE中使用多線程庫(kù),首先要激活“Project | Settings”屬性頁(yè)。然后選擇“C/C++”選項(xiàng)卡。接著在“Category”下拉列表框中選擇“Code Generation”,然后在“Use Runtime Library ”下拉列表框中選擇“Multithreaded”。對(duì)于Visual C++ 7 .NET IDE,選擇“Project |Properties”。然后選擇“C/C++”條目,并加亮顯示“Code Generation”。最后,將“Multithreaded”選擇為運(yùn)行庫(kù)。

3.4.3 線程的掛起和恢復(fù)

線程的執(zhí)行可以通過(guò)調(diào)用SuspendThread()來(lái)掛起。可以通過(guò)調(diào)用ResumeThread()來(lái)恢復(fù)它。這兩個(gè)函數(shù)的原型如下:

DWORD SuspendThread(HANDLE hThread);

DWORD ResumeThread(HANDLE hThread);

兩個(gè)函數(shù)都通過(guò)hThread來(lái)傳遞線程的句柄。

每個(gè)執(zhí)行的線程都有與其相關(guān)的掛起計(jì)數(shù)。如果這個(gè)計(jì)數(shù)為0,那么不會(huì)掛起線程。如果為非0值,則線程就會(huì)處于掛起狀態(tài)。每次調(diào)用SuspendThread()都會(huì)增加這個(gè)計(jì)數(shù)。每次調(diào)用ResumeThread()都會(huì)減小這個(gè)掛起計(jì)數(shù)。掛起的線程只有在它的掛起計(jì)數(shù)達(dá)到0時(shí)才會(huì)恢復(fù)。因此,為了恢復(fù)一個(gè)掛起的線程,對(duì)ResumeThread()的調(diào)用次數(shù)必須與對(duì)SuspendThread()的調(diào)用次數(shù)相等。

這兩個(gè)函數(shù)都返回線程先前的掛起計(jì)數(shù),如果發(fā)生錯(cuò)誤,返回值為–1。

3.4.4 改變線程的優(yōu)先級(jí)

在Windows中,每個(gè)線程都與一個(gè)優(yōu)先級(jí)設(shè)置相關(guān)。線程的優(yōu)先級(jí)決定了線程接收的CPU時(shí)間的多少。低優(yōu)先級(jí)的線程接收比較少的時(shí)間,高優(yōu)先級(jí)的線程接收比較多的時(shí)間。當(dāng)然,線程接收的CPU時(shí)間的多少對(duì)于它的執(zhí)行性能以及它與系統(tǒng)中當(dāng)前執(zhí)行的其他線程之間的交互有著深遠(yuǎn)的影響。

在Windows中,線程優(yōu)先級(jí)的設(shè)置是兩個(gè)值的組合:進(jìn)程總體的優(yōu)先級(jí)類別以及相對(duì)于這個(gè)優(yōu)先級(jí)類別的各個(gè)線程的優(yōu)先級(jí)設(shè)置。也就是說(shuō),線程實(shí)際的優(yōu)先級(jí)由進(jìn)程的優(yōu)先級(jí)類別和各個(gè)線程的優(yōu)先級(jí)的組合來(lái)確定。后面會(huì)逐一講述。

1. 優(yōu)先級(jí)類別

在默認(rèn)情況下,進(jìn)程具有普通的優(yōu)先級(jí)類別,大多數(shù)程序在其執(zhí)行的聲明周期內(nèi)保持這個(gè)普通的優(yōu)先級(jí)類別。盡管在本章的示例中沒(méi)有改變優(yōu)先級(jí)類別,但是為了完整起見(jiàn),在此給出了線程優(yōu)先級(jí)類別的簡(jiǎn)單概況。

Windows定義了6個(gè)優(yōu)先級(jí)類別,相應(yīng)的值以從高到低的順序顯示如下:

REALTIME_PRIORITY_CLASS

HIGH_PRIORITY_CLASS

ABOVE_NORMAL_PRIORITY_CLASS

NORMAL_PRIORITY_CLASS

BELOW_NORMAL_PRIORITY_CLASS

IDLE_PRIORITY_CLASS

在默認(rèn)情況下,程序的優(yōu)先級(jí)類別為NORMAL_PRIORITY_CLASS。通常,您不需要改變程序的優(yōu)先級(jí)類別。事實(shí)上,改變進(jìn)程的優(yōu)先級(jí)類別對(duì)于整個(gè)計(jì)算機(jī)系統(tǒng)的性能會(huì)有負(fù)面的影響。例如,如果您將一個(gè)程序的優(yōu)先級(jí)類別增加到REALTIME_PRIORITY_CLASS,它就會(huì)支配CPU。對(duì)于某些特殊的應(yīng)用程序,可能需要增加應(yīng)用程序的優(yōu)先級(jí)類別,但通常并不需要。如前所述,本章的應(yīng)用程序沒(méi)有改變優(yōu)先級(jí)類別。

當(dāng)確實(shí)需要改變程序的優(yōu)先級(jí)類別時(shí),可以調(diào)用SetPriorityClass()。可以調(diào)用GetPriorityClass()來(lái)獲取當(dāng)前的優(yōu)先級(jí)類別。這兩個(gè)函數(shù)的原型如下:

DWORD GetPriorityClass(HANDLE hApp);

BOOL SetPriorityClass(HANDLE hApp, DWORD priority);

在此,hApp是進(jìn)程的句柄。GetPriorityClass()返回應(yīng)用程序的優(yōu)先級(jí)類別,如果失敗的話,返回0。對(duì)于SetPriorityClass(),priority指定了進(jìn)程的新優(yōu)先級(jí)類別。

2. 線程優(yōu)先級(jí)

對(duì)于給定的優(yōu)先級(jí)類別,各個(gè)線程的優(yōu)先級(jí)確定了它在進(jìn)程內(nèi)接收的CPU時(shí)間的多少。當(dāng)線程第一次創(chuàng)建時(shí),它具有普通的優(yōu)先級(jí),但是您可以改變線程的優(yōu)先級(jí)—— 即使在它執(zhí) 行時(shí)。

可以通過(guò)調(diào)用GetThreadPriority()來(lái)獲取線程的優(yōu)先級(jí)設(shè)置。可以使用SetThreadPriority()來(lái)增加或者減小線程的優(yōu)先級(jí)。這兩個(gè)函數(shù)的原型如下:

BOOL SetThreadPriority(HANDLE hThread, int priority);

int GetThreadPriority(HANDLE hThread);

對(duì)于這兩個(gè)函數(shù)而言,hThread是線程的句柄。對(duì)于SetThreadPriority(),priority是新的優(yōu)先級(jí)設(shè)置。如果發(fā)生錯(cuò)誤,則返回值為0;否則,返回非0值。GetThreadPriority()會(huì)返回當(dāng)前的優(yōu)先級(jí)設(shè)置。優(yōu)先級(jí)設(shè)置按照從高到低的順序如表3-1所示。

表3-1 優(yōu)先級(jí)設(shè)置

線程優(yōu)先級(jí)

THREAD_PRIORITY_TIME_CRITICAL

15

THREAD_PRIORITY_HIGHEST

2

THREAD_PRIORITY_ABOVE_NORMAL

1

THREAD_PRIORITY_NORMAL

0

THREAD_PRIORITY_BELOW_NORMAL

-1

THREAD_PRIORITY_LOWEST

-2

THREAD_PRIORITY_IDLE

-15

這些值相對(duì)于進(jìn)程的優(yōu)先級(jí)類別或增或減。通過(guò)組合進(jìn)程的優(yōu)先級(jí)類別和線程的優(yōu)先級(jí),Windows向應(yīng)用程序提供了31個(gè)不同的優(yōu)先級(jí)設(shè)置的支持。

如果有錯(cuò)誤發(fā)生,則GetThreadPriority()返回THREAD_PRIORITY_ERROR_RETURN。

在大多數(shù)情況下,如果線程具有普通的優(yōu)先級(jí)類別,那么可以隨意地改變它的優(yōu)先級(jí)設(shè)置,而不必?fù)?dān)心會(huì)給整個(gè)系統(tǒng)的性能帶來(lái)災(zāi)難性的影響。您將會(huì)看到,在下面部分開(kāi)發(fā)的線程控制面板中,可以改變進(jìn)程內(nèi)線程的優(yōu)先級(jí)設(shè)置(但是不能改變優(yōu)先級(jí)類別)。

3.4.5 獲取主線程的句柄

主線程的執(zhí)行是可以控制的。為此,需要獲取它的句柄。做到這一點(diǎn)最簡(jiǎn)單的方法是調(diào)用GetCurrentThread(),其原型如下:

HANDLE GetCurrentThread(void);

這個(gè)函數(shù)返回當(dāng)前線程的偽句柄(pseudohandle)。之所以稱之為偽句柄,是因?yàn)樗且粋€(gè)預(yù)定義的值,總是引用當(dāng)前的線程,而不是引用指定的調(diào)用線程。然而,它能夠用在任何可以使用普通線程處理的地方。

3.4.6 同步

在使用多線程或多進(jìn)程時(shí),有時(shí)需要調(diào)整兩個(gè)或者多個(gè)線程(或者進(jìn)程)之間的活動(dòng)。這個(gè)過(guò)程稱為同步。當(dāng)兩個(gè)或者多個(gè)線程需要訪問(wèn)共享資源,而這個(gè)共享資源在同一時(shí)刻只能由一個(gè)線程使用時(shí),就需要使用同步。例如,當(dāng)一個(gè)線程在寫文件時(shí),在此時(shí)必須阻止另一個(gè)線程也這么做。同步的另一個(gè)原因是有時(shí)線程需要等待由另一個(gè)線程引發(fā)的事件。在此情況下,必須采取某種措施將第一個(gè)線程保持掛起狀態(tài),直到這個(gè)事件發(fā)生。隨后等待的線程必須恢復(fù) 執(zhí)行。

通常某個(gè)任務(wù)會(huì)處于兩種狀態(tài)。首先,它可能正在執(zhí)行(或者在獲得它的時(shí)間段時(shí)就開(kāi)始執(zhí)行)。另外,任務(wù)可能被阻塞,等待某個(gè)資源或者事件。在此情況下其執(zhí)行被掛起,直到所需的資源可以使用或者所等待的事件發(fā)生。

如果您對(duì)于同步問(wèn)題或者它的常用解決方案(信號(hào)量)不熟悉,下面的部分將對(duì)此進(jìn)行討論。

1. 理解同步問(wèn)題

Windows必須提供某種特殊的服務(wù)來(lái)允許對(duì)共享資源的訪問(wèn)同步,因?yàn)槿绻麤](méi)有操作系統(tǒng)的協(xié)助,進(jìn)程或者線程就沒(méi)有辦法得知它是否在單獨(dú)訪問(wèn)某個(gè)資源。為了理解這個(gè)問(wèn)題,假定您在為一個(gè)沒(méi)有提供任何同步支持的多任務(wù)操作系統(tǒng)編寫程序,并且假定您具有兩個(gè)并發(fā)執(zhí)行的線程A和B,它們都不時(shí)地訪問(wèn)某個(gè)資源R(如磁盤文件),這個(gè)資源在某個(gè)時(shí)刻只能被一個(gè)線程訪問(wèn)。為了在一個(gè)線程使用這個(gè)資源時(shí)阻止另一個(gè)線程訪問(wèn)它,您嘗試了下面的解決方案。首先,創(chuàng)建了一個(gè)初始化值為0并且兩個(gè)線程都可以訪問(wèn)的變量,名為flag。然后,在使用訪問(wèn)R的每段代碼之前,等待flag被清0,然后設(shè)置flag,訪問(wèn)R,最后將flag清0。也就是說(shuō),在每個(gè)線程訪問(wèn)R之前,執(zhí)行如下的代碼:

while(flag) ; // wait for flag to be cleared

flag = 1; // set flag

// ... access resource R ...

flag = 0; // clear the flag

這段代碼隱含的概念是,如果設(shè)置了flag,則兩個(gè)線程都不能夠訪問(wèn)R。從概念上講,這種方法是正確的解決方案。然而,實(shí)際上它遠(yuǎn)遠(yuǎn)沒(méi)有達(dá)到要求,原因很簡(jiǎn)單:它并非總是有效!讓我們看一下原因。

使用剛才給定的代碼,有可能兩個(gè)進(jìn)程同時(shí)訪問(wèn)R。while循環(huán)在本質(zhì)上執(zhí)行重復(fù)的加載和比較flag上的指令。換句話說(shuō),它一直在測(cè)試flag的值。當(dāng)flag被清0的時(shí)候,代碼的下一行將設(shè)置flag的值。問(wèn)題在于,這兩個(gè)操作有可能在兩個(gè)不同的時(shí)間段執(zhí)行。在兩個(gè)時(shí)間段之間,flag的值有可能被另一個(gè)線程訪問(wèn),從而R被兩個(gè)線程同時(shí)訪問(wèn)。為了理解這一點(diǎn),假定線程A進(jìn)入while循環(huán),發(fā)現(xiàn)flag為0,這是訪問(wèn)R的綠燈。然而,在將flag設(shè)置為1之前,其時(shí)間段用盡,線程B恢復(fù)執(zhí)行。如果B執(zhí)行了它的while,它也發(fā)現(xiàn)flag沒(méi)有被設(shè)置,并且認(rèn)為它可以安全地訪問(wèn)R。然而,當(dāng)A重新開(kāi)始時(shí),它也會(huì)訪問(wèn)R。問(wèn)題的關(guān)鍵在于對(duì)flag的測(cè)試和設(shè)置沒(méi)有包含在一個(gè)連續(xù)的操作中,而是可以被分為兩個(gè)部分,正如剛才說(shuō)明的那樣。無(wú)論您如何努力,都沒(méi)有辦法只使用應(yīng)用層的代碼以絕對(duì)保證在同一時(shí)刻只有一個(gè)線程訪問(wèn)R。

對(duì)同步問(wèn)題的解決方案簡(jiǎn)單而優(yōu)雅。操作系統(tǒng)(在Windows中)提供了一個(gè)例程,在一個(gè)連續(xù)的操作中完成對(duì)flag的測(cè)試和設(shè)置(如果可能的話)。用操作系統(tǒng)工程師的話來(lái)說(shuō),這就是所謂的測(cè)試和置位(test and set)操作。由于歷史的原因,用來(lái)控制對(duì)共享資源的訪問(wèn)并提供線程(以及進(jìn)程)間同步的標(biāo)記被稱為信號(hào)量。信號(hào)量是Windows同步系統(tǒng)的核心。

2. Windows的同步對(duì)象

Windows支持幾種類型的同步對(duì)象。第一種類型是經(jīng)典的信號(hào)量。當(dāng)使用信號(hào)量時(shí),可以完全同步資源,在此情況下只有一個(gè)進(jìn)程或者線程在同一時(shí)刻可以訪問(wèn)這個(gè)資源,或者信號(hào)量允許不超過(guò)一定數(shù)量的進(jìn)程或者線程在同一時(shí)刻訪問(wèn)資源。信號(hào)量使用計(jì)數(shù)器來(lái)實(shí)現(xiàn),當(dāng)某個(gè)任務(wù)使用信號(hào)量時(shí),計(jì)數(shù)器減小;當(dāng)這個(gè)任務(wù)釋放信號(hào)量時(shí),計(jì)數(shù)器增加。

第二個(gè)同步對(duì)象是互斥體信號(hào)量,或者簡(jiǎn)稱為互斥體。互斥體將一個(gè)資源同步,保證在任何時(shí)候都只有一個(gè)線程或者進(jìn)程來(lái)訪問(wèn)它。在本質(zhì)上,互斥體是標(biāo)準(zhǔn)信號(hào)量的一個(gè)特殊版本。

第三個(gè)同步對(duì)象是事件對(duì)象。它可以用來(lái)阻塞對(duì)某個(gè)資源的訪問(wèn),直到某個(gè)其他的進(jìn)程或者線程發(fā)送信號(hào),通知可以使用資源(也就是一個(gè)事件對(duì)象發(fā)送某個(gè)指定的事件發(fā)生的信號(hào))。

第四個(gè)同步對(duì)象是可等待計(jì)時(shí)器。可等待計(jì)時(shí)器阻塞線程的執(zhí)行,直到指定的時(shí)間。也可以創(chuàng)建計(jì)時(shí)器序列,這是一個(gè)計(jì)時(shí)器的列表。

可以使用臨界區(qū)對(duì)象將一個(gè)代碼段放入臨界區(qū),從而阻止在同一時(shí)刻一個(gè)以上的線程使用這段代碼。當(dāng)一個(gè)線程進(jìn)入臨界區(qū)時(shí),其他線程只有在第一個(gè)線程離開(kāi)整個(gè)臨界區(qū)時(shí)才可以使用它。

本章使用的惟一的同步對(duì)象是互斥體,下面的部分將對(duì)其進(jìn)行描述。然而,C++程序員可以使用所有的Windows定義的同步對(duì)象。如前所述,這是使得C++依賴于操作系統(tǒng)處理多線程的主要優(yōu)點(diǎn)之一:所有的多線程特性都在您的控制之中。

3. 使用互斥體同步線程

如前所述,互斥體是一種特殊的信號(hào)量,在給定的時(shí)間內(nèi),只允許一個(gè)線程訪問(wèn)某個(gè)資源。在使用互斥體之前,必須使用CreatMutex()創(chuàng)建一個(gè)互斥體,函數(shù)原型如下:

HANDLE CreateMutex(LPSECURITY_ATTRIBUTES secAttr,

BOOL acquire,

LPCSTR name);

在此,secAttr是用來(lái)描述安全屬性的指針。如果secAttr為NULL,則使用默認(rèn)的安全描 述符。

如果創(chuàng)建的線程需要互斥體的控制,則acquire為true,否則為false。

name參數(shù)指向一個(gè)字符串,這個(gè)字符串是互斥體對(duì)象的名稱。互斥體是一個(gè)全局對(duì)象,它可能被其他進(jìn)程使用。為此,當(dāng)兩個(gè)進(jìn)程都打開(kāi)了使用相同名稱的互斥體時(shí),二者引用了相同的互斥體。使用這種方法可以將兩個(gè)進(jìn)程同步。這個(gè)名稱也可以為NULL,在此情況下這個(gè)信號(hào)量被限制在一個(gè)進(jìn)程之內(nèi)。

如果成功,則CreatMutex()函數(shù)返回信號(hào)量的句柄,否則,返回NULL。當(dāng)主進(jìn)程結(jié)束時(shí),互斥體的句柄則自動(dòng)關(guān)閉。當(dāng)不再需要時(shí),可以調(diào)用CloseHandle()來(lái)顯式地關(guān)閉互斥體的句柄。

當(dāng)創(chuàng)建信號(hào)量時(shí),可以調(diào)用兩個(gè)相關(guān)的函數(shù)來(lái)使用它:WaitForSingleObject()和ReleaseMutex()。這兩個(gè)函數(shù)的原型如下:

DWORD WaitForSingleObject(HANDLE hObject, DWORD howLong);

BOOL ReleaseMutex(HANDLE hMutex);

WaitForSingleObject()等待一個(gè)同步對(duì)象,直到這個(gè)對(duì)象可以使用或者超時(shí)之后才會(huì)返回。在使用互斥體時(shí),hObject是互斥體的句柄。howLong參數(shù)以毫秒為單位指定調(diào)用例程的等待時(shí)間。當(dāng)這個(gè)時(shí)間用盡時(shí),會(huì)返回超時(shí)錯(cuò)誤。為了無(wú)限期地等待,可以使用值INFINITE。當(dāng)成功時(shí)(也就是訪問(wèn)被準(zhǔn)許),這個(gè)函數(shù)返回WAIT_OBJECT_0。當(dāng)發(fā)生超時(shí)時(shí),返回WAIT_TIMEOUT。

ReleaseMutex()釋放互斥體,并允許其他線程獲取它。在此,hMutex是互斥體的句柄。如果成功,則函數(shù)返回非0值;如果失敗,則返回0。

為了使用互斥體控制對(duì)共享資源的訪問(wèn),封裝了訪問(wèn)在調(diào)用WaitForSingleObject()和ReleaseMutex()之間的資源的代碼,如下面的代碼所示(當(dāng)然,超時(shí)期限隨應(yīng)用程序的不同而 不同)。

if(WaitForSingleObject(hMutex, 10000)==WAIT_TIMEOUT) {

// handle time-out error

}

// access the resource

ReleaseMutex(hMutex);

通常,您會(huì)選擇足夠長(zhǎng)的超時(shí)期限來(lái)適應(yīng)程序的操作。如果在開(kāi)發(fā)多線程應(yīng)用程序時(shí)重復(fù)出現(xiàn)超時(shí)錯(cuò)誤,那么通常意味著您創(chuàng)建了死鎖條件。當(dāng)一個(gè)線程等待另一個(gè)線程永遠(yuǎn)都不會(huì)釋放的互斥體時(shí),就會(huì)發(fā)生死鎖。

posted on 2006-11-10 10:06 大龍 閱讀(7408) 評(píng)論(5)  編輯 收藏 引用

評(píng)論

# re: Windows線程函數(shù)概述 - 《C++編程藝術(shù)》[未登錄](méi) 2007-12-14 12:21 Corner Zhang

好文,對(duì)我很有幫助,學(xué)習(xí)了!  回復(fù)  更多評(píng)論   

# re: Windows線程函數(shù)概述 - 《C++編程藝術(shù)》 2010-03-12 10:29 invenco

很不錯(cuò)  回復(fù)  更多評(píng)論   

# re: Windows線程函數(shù)概述 - 《C++編程藝術(shù)》 2010-09-28 12:56 Vendy

寫得很不錯(cuò),很受益,頂!@invenco
  回復(fù)  更多評(píng)論   

# re: Windows線程函數(shù)概述 - 《C++編程藝術(shù)》 2012-04-12 09:22 misserwell

請(qǐng)問(wèn)線程,進(jìn)程的創(chuàng)建,是不是再不同的OS 里有不同的方法》 ?
我很好奇, 在 linux 里 好像用 pthread_create 去創(chuàng)建線程, 據(jù)你所說(shuō), windows里 用CreateThread , 我說(shuō)的對(duì)嗎? 希望你再多講講  回復(fù)  更多評(píng)論   

# re: Windows線程函數(shù)概述 - 《C++編程藝術(shù)》 2012-06-09 19:48 LXJ

請(qǐng)問(wèn)一下,什么是線程函數(shù)?  回復(fù)  更多評(píng)論   


只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲免费视频观看| 99国内精品| 欧美ed2k| 欧美大片一区| 欧美高清在线视频观看不卡| 欧美国产综合一区二区| 欧美乱大交xxxxx| 欧美香蕉视频| 国产一区二区黄色| 亚洲国产精品成人综合| 99精品国产在热久久| 亚洲午夜未删减在线观看| 久久福利视频导航| 欧美成人精品1314www| 91久久精品一区二区三区| 久久精品视频免费| 免费在线看一区| 99v久久综合狠狠综合久久| 午夜精品久久久久久久99水蜜桃 | 亚洲国产三级网| 日韩一二三区视频| 欧美一区二区三区免费在线看| 久久免费精品视频| 欧美日韩精品在线| 国语自产精品视频在线看一大j8 | 亚洲天堂成人在线观看| 久久国产精品一区二区三区| 欧美日韩国产精品| 樱桃成人精品视频在线播放| 亚洲一区二区精品在线| 欧美国产视频在线| 亚洲欧美精品在线观看| 欧美激情第一页xxx| 国产一区视频在线观看免费| 99re6热在线精品视频播放速度| 久久aⅴ国产欧美74aaa| 99视频在线观看一区三区| 美女爽到呻吟久久久久| 国产午夜精品在线| 亚洲欧美日韩成人| 亚洲伦理一区| 欧美成人激情在线| 樱桃视频在线观看一区| 午夜视频一区二区| 亚洲伦理中文字幕| 欧美精品网站| 亚洲精品看片| 欧美寡妇偷汉性猛交| 欧美中文字幕不卡| 国产一区二区0| 欧美中文在线视频| 亚洲欧美999| 国产精品一区二区女厕厕| 亚洲一区二区免费看| 日韩视频国产视频| 欧美日韩国产在线播放网站| 亚洲免费电影在线观看| 亚洲国产精品久久久久婷婷老年 | 99香蕉国产精品偷在线观看| 欧美精品日韩一本| 一本色道久久综合亚洲91| 亚洲国产天堂久久国产91| 久热国产精品视频| 亚洲黄色成人久久久| 亚洲电影毛片| 男人的天堂亚洲在线| 亚洲日本一区二区三区| 欧美一区国产在线| 欧美精品一卡| 一区二区欧美亚洲| 在线视频你懂得一区| 国产精品成人一区二区三区夜夜夜 | 久久国产一区| 午夜一区在线| 激情欧美一区二区三区| 老司机精品福利视频| 久久精品久久99精品久久| 影音先锋日韩资源| 久久午夜国产精品| 久久久久欧美精品| 亚洲激情二区| 91久久精品美女| 欧美美女喷水视频| 亚洲欧美在线观看| 欧美一区二区精品久久911| 国产综合婷婷| 榴莲视频成人在线观看| 久久偷窥视频| 亚洲一区二区三区中文字幕| 亚洲欧美成人一区二区三区| 激情久久婷婷| 亚洲国产视频直播| 国产精品手机在线| 久久综合色8888| 欧美日韩国产一区二区三区| 欧美一区二区三区免费观看| 久久美女性网| 亚洲一区二区少妇| 久久久精彩视频| 亚洲视频精品| 老**午夜毛片一区二区三区| 亚洲影视综合| 欧美xxx成人| 久久精品国产99精品国产亚洲性色| 免费永久网站黄欧美| 久久成人免费| 欧美日韩在线免费视频| 欧美国产日本| 国产欧美丝祙| 亚洲经典在线| 狠狠色综合色综合网络| 一本久久a久久免费精品不卡| 激情欧美一区二区三区在线观看| 亚洲国产婷婷| 亚洲视频久久| 亚洲乱码久久| 久久人人97超碰人人澡爱香蕉| 亚洲综合日韩在线| 欧美人妖在线观看| 欧美激情二区三区| 一区精品久久| 久久国产福利| 久久经典综合| 国产美女精品一区二区三区| 欧美1区视频| 在线观看精品| 久久国产精品久久w女人spa| 午夜国产精品影院在线观看 | 好看的日韩视频| 亚洲一区二区三区久久| 一本色道久久加勒比精品| 猛干欧美女孩| 欧美大片免费久久精品三p| 国产亚洲精品美女| 午夜在线视频一区二区区别| 性欧美xxxx视频在线观看| 国产精品视频| 中文国产成人精品久久一| 99精品99| 欧美日韩一区在线观看| 9人人澡人人爽人人精品| 午夜精品久久久99热福利| 欧美激情一区在线| 亚洲人成免费| 日韩一二在线观看| 欧美激情在线狂野欧美精品| 亚洲国产日韩精品| 亚洲一区二区av电影| 国产欧美1区2区3区| 欧美在线视频免费观看| 老司机午夜精品| 亚洲精品一区二| 欧美日韩亚洲另类| 亚洲一线二线三线久久久| 久久九九国产精品| 亚洲福利视频在线| 欧美电影在线免费观看网站| aa国产精品| 久久精品国产96久久久香蕉 | 亚洲无线视频| 国产乱码精品1区2区3区| 久久精品综合| 亚洲日本中文| 欧美在线精品一区| 91久久精品www人人做人人爽 | 亚洲毛片一区| 欧美一区二区视频观看视频| 好吊一区二区三区| 欧美日韩午夜剧场| 久久精品2019中文字幕| 亚洲国产欧美一区二区三区同亚洲 | 国产视频亚洲精品| 免费观看亚洲视频大全| 日韩特黄影片| 久久亚洲精品网站| 99在线精品视频| 国产一区在线观看视频| 欧美久久精品午夜青青大伊人| 亚洲欧美国产高清va在线播| 欧美大片免费久久精品三p| 欧美一级精品大片| 亚洲精品久久久久久久久| 国产欧美大片| 欧美日韩国产一区精品一区 | 欧美在线精品免播放器视频| 麻豆精品91| 一本色道久久综合亚洲精品不卡| 国产精品亚洲一区| 欧美大片免费观看| 久久婷婷色综合| 亚洲欧美成人| 日韩视频精品| 亚洲福利免费| 久久综合狠狠综合久久激情| 亚洲欧美日韩网| 一区二区三区精密机械公司| 亚洲国产高清一区二区三区| 国内外成人免费激情在线视频网站 | 亚洲欧美日韩一区二区| 日韩视频永久免费|