




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第3章Windows程序的執(zhí)行單元——線程第3章Windows程序的執(zhí)行單元——線程3.1多線程線程的創(chuàng)建線程內(nèi)核對(duì)象線程的終止線程的優(yōu)先級(jí)C/C++運(yùn)行期庫(kù)3.1多線程線程的創(chuàng)建線程的創(chuàng)建多線程并發(fā)執(zhí)行,os為其輪流分配cpu時(shí)間片一般情況,主線程接受用戶輸入,顯示運(yùn)行結(jié)果;新創(chuàng)建的線程來(lái)處理長(zhǎng)時(shí)間的操作,如讀寫文件、訪問(wèn)網(wǎng)絡(luò)等,這樣即便程序忙于繁重的工作也可以由專門的線程響應(yīng)用戶命令每個(gè)線程必須擁有入口點(diǎn)函數(shù),主線程的為main。輔助線程入口點(diǎn)函數(shù)稱為線程函數(shù),定義如下:DWORDWINAPIThreadProc(LPVOIDlpParam);
函數(shù)名稱ThreadProc可以是任意的線程的創(chuàng)建多線程并發(fā)執(zhí)行,os為其輪流分配cpu時(shí)間片線程的創(chuàng)建#defineWINAPI_stdcall;_stdcall是新標(biāo)準(zhǔn)c/c++調(diào)用方法,與標(biāo)準(zhǔn)c調(diào)用_cdecl相比,參數(shù)進(jìn)棧次序相同,從右到左,但_stdcall采用自動(dòng)清棧方式,而_cdecl采用手工清棧方式。由windows操作系統(tǒng)調(diào)用的函數(shù)(回調(diào)函數(shù))必須聲明為_stdcall沒(méi)有顯示說(shuō)明的話,為_cdecl調(diào)用方式線程的創(chuàng)建#defineWINAPI_stdcall;線程的創(chuàng)建創(chuàng)建新線程用CreateThreadHANDLE
CreateThread(
LPSECURITY_ATTRIBUTES
lpsa,DWORD
cbStack,LPTHREAD_START_ROUTINE
lpStartAddr,LPVOID
lpvThreadParam,DWORD
fdwCreate, LPDWORD
lpIDThread
);
線程的創(chuàng)建創(chuàng)建新線程用CreateThread線程的創(chuàng)建lpsa
[in]Ignored.MustbeNULL.指定線程安全屬性cbStack
[in]指定線程堆棧大小,NULL為默認(rèn)大小lpStartAddr
[in]線程函數(shù)起始地址lpvThreadParam
[in]Longpointertoasingle32-bitparametervaluepassedtothethread.fdwCreate
[in]Specifiesflagsthatcontrolthecreationofthethread.0表示線程創(chuàng)建后立即運(yùn)行l(wèi)pIDThread
[out]Longpointertoa32-bitvariablethatreceivesthethreadidentifier.IfthisparameterisNULL,thethreadidentifierisnotreturned.線程的創(chuàng)建lpsaWaitForSingleObjectDWORD
WaitForSingleObject(HANDLE
hHandle,DWORD
dwMilliseconds
);
Thisfunctionreturnswhenthespecifiedobjectisinthesignaledstate(受信狀態(tài))orwhenthetime-outintervalelapses.該函數(shù)用于等待指定的對(duì)象(hHandle)變成受信狀態(tài)。 說(shuō)明:在例03ThreadDemo工程中,用于等待輔助線程對(duì)應(yīng)的函數(shù)ThreadProc()執(zhí)行完成。調(diào)用該函數(shù)將阻塞主線程。一個(gè)可執(zhí)行對(duì)象有兩種狀態(tài):未受信、受信。線程對(duì)象只有當(dāng)線程結(jié)束才為受信態(tài)。WaitForSingleObjectDWORDWaitFWaitForSingleObjecthHandle
[in]Handletotheobject.Foralistoftheobjecttypeswhosehandlescanbespecified,seetheRemarkssection.dwMilliseconds
[in]Specifiesthetime-outinterval,inmilliseconds.Thefunctionreturnsiftheintervalelapses,eveniftheobject'sstateisnonsignaled.IfdwMillisecondsiszero,thefunctionteststheobject'sstateandreturnsimmediately.IfdwMillisecondsisINFINITE,thefunction'stime-outintervalneverelapses.WaitForSingleObjecthHandle線程的創(chuàng)建例子程序線程的創(chuàng)建例子程序3.1.2線程內(nèi)核對(duì)象線程內(nèi)核對(duì)象是一個(gè)包含了線程狀態(tài)信息的數(shù)據(jù)結(jié)構(gòu)。每次對(duì)CreateThread的成功調(diào)用,系統(tǒng)都會(huì)在內(nèi)部為新的線程分配一個(gè)內(nèi)核對(duì)象。系統(tǒng)對(duì)線程的管理是依靠訪問(wèn)線程內(nèi)核對(duì)象來(lái)實(shí)現(xiàn)的。1.線程上下文CONTEXT反映該線程上次運(yùn)行時(shí)CPU寄存器的狀態(tài)。3.1.2線程內(nèi)核對(duì)象線程內(nèi)核對(duì)象是一個(gè)包含了線程狀態(tài)信息2.線程創(chuàng)建例子中使用計(jì)數(shù)調(diào)用CreateThread后,使用計(jì)數(shù)=2,線程函數(shù)返回,系統(tǒng)將使使用計(jì)數(shù)減少1,即使用計(jì)數(shù)=1,接下來(lái)又調(diào)用CloseHandle使使用計(jì)數(shù)減1,即最后使用計(jì)數(shù)=0,該內(nèi)存空間被收回。2.線程創(chuàng)建例子中使用計(jì)數(shù)調(diào)用CreateThread后,CONTEXT(上下文,即寄存器的狀態(tài)),恢復(fù)現(xiàn)場(chǎng)必須使用使用計(jì)數(shù)(2):CreateThread返回句柄,相當(dāng)于打開一次內(nèi)核對(duì)象,促使該值+1,所以初始值=2;另外,OpenThread使該值+1,GetCurrentThread不會(huì)改變?cè)撝禃和4螖?shù)(1):1表示處于暫停狀態(tài),這樣就不會(huì)被調(diào)度到CPU中,給CreateThread時(shí)間對(duì)線程進(jìn)行初始化。初始化之后,如果未傳遞CREATE_SUSPENDED(掛起)標(biāo)志,暫停次數(shù)=0,該線程處于可調(diào)度狀態(tài)。喚醒用ResumeThread(),該函數(shù)使暫停次數(shù)-1,掛起用SuspendThread(),該函數(shù)使暫停次數(shù)+1,一個(gè)線程可以被掛起若干次,這就需要喚醒同樣次數(shù)才能使暫停次數(shù)=0,才能處于可調(diào)度狀態(tài),大約每隔20ms,進(jìn)行一次時(shí)間片輪轉(zhuǎn),os選擇新線程,將其上下文裝入cpu寄存器,組織起運(yùn)行。退出代碼(STILL_ALIVE):即線程函數(shù)的返回值,可以用GetExitCodeThread得到線程退出代碼,所以可以當(dāng)作自定義的返回值來(lái)表示線程的執(zhí)行結(jié)果。是否受信(FALSE):只有當(dāng)線程結(jié)束時(shí),該值才為TRUE…CONTEXT(上下文,即寄存器的狀態(tài)),恢復(fù)現(xiàn)場(chǎng)必須使用使3.1.3線程的終止線程終止的4種方法線程函數(shù)自然退出ExitThreadTerminateThread造成無(wú)法作清除工作,ExitProcess不提倡例子程序02ExitThread3.1.3線程的終止線程終止的4種方法3.1.4線程的優(yōu)先級(jí)每個(gè)線程被賦予一個(gè)優(yōu)先級(jí)號(hào),0——31,0最低,31最高,調(diào)度時(shí)選擇最高的,并采用搶占式優(yōu)先調(diào)度算法。eg:IEexplor的線程優(yōu)先級(jí)就很高。設(shè)置優(yōu)先級(jí)用SetThreadPriority()。BOOL
SetThreadPriority(HANDLE
hThread,int
nPriority
);
3.1.4線程的優(yōu)先級(jí)每個(gè)線程被賦予一個(gè)優(yōu)先級(jí)號(hào),0——3THREAD_PRIORITY_TIME_CRITICAL實(shí)時(shí)THREAD_PRIORITY_HIGHEST最高THREAD_PRIORITY_ABOVE_NORMAL高于正常THREAD_PRIORITY_NORMAL正常THREAD_PRIORITY_BELOW_NORMAL低于正常THREAD_PRIORITY_LOWEST最低THREAD_PRIORITY_ABOVE_IDLE高于最低THREAD_PRIORITY_IDLE空閑THREAD_PRIORITY_TIME_CRITICAL線程的優(yōu)先級(jí)例子程序線程的優(yōu)先級(jí)例子程序3.1.5C/C++運(yùn)行期庫(kù)在實(shí)際的開發(fā)過(guò)程中,一般使用c/c++運(yùn)行期函數(shù)_beginthreadx代替CreateThread函數(shù)。_beginthreadx首先申請(qǐng)一些用于線程同步的變量,然后調(diào)用CreateThreadVc++默認(rèn)的c/c++運(yùn)行期庫(kù)不支持_beginthreadx,需要設(shè)置”Project/settings/c/c++/codegeneration/…./選中multithreadDLL”即可。需要#include<process.h>同樣,使用_endthreadex代替ExitThread。該函數(shù)首先釋放用于線程同步的變量,再調(diào)用ExitThread3.1.5C/C++運(yùn)行期庫(kù)在實(shí)際的開發(fā)過(guò)程中,一般使用c3.2線程同步同步可以保證在一個(gè)時(shí)間內(nèi)只有一個(gè)線程對(duì)某個(gè)共享資源有控制權(quán)。臨界區(qū)對(duì)象事件內(nèi)核對(duì)象線程局部存儲(chǔ)(TLS)3.2線程同步同步可以保證在一個(gè)時(shí)間內(nèi)只有一個(gè)線程對(duì)某個(gè)共3.2線程同步解決同步問(wèn)題的方法:臨界區(qū)對(duì)象:線程獨(dú)占,等待的線程掛起,不可調(diào)度互鎖函數(shù):單一變量同步問(wèn)題事件內(nèi)核對(duì)象:是否”受信”,通知信號(hào)量?jī)?nèi)核對(duì)象:信號(hào)量計(jì)數(shù),多個(gè)線程共享,用于Socket(套接字)程序中線程同步互斥內(nèi)核對(duì)象:線程獨(dú)占,等待的線程可調(diào)度,用于保護(hù)內(nèi)存3.2線程同步解決同步問(wèn)題的方法:3.2.1臨界區(qū)對(duì)象1.為什么要線程同步?當(dāng)多個(gè)線程在同一個(gè)進(jìn)程中執(zhí)行時(shí),可能有不止一個(gè)線程同時(shí)執(zhí)行同一段代碼,訪問(wèn)同一段內(nèi)存中的數(shù)據(jù)。線程同步產(chǎn)生的問(wèn)題——一個(gè)錯(cuò)誤的例子03ConntErr→線程函數(shù)ThreadFunc同時(shí)增加全局變量g_nCount1和g_nConnt2的計(jì)數(shù),原則上兩個(gè)變量的值應(yīng)該相等,但由于是兩個(gè)線程同時(shí)訪問(wèn)這兩個(gè)全局變量,最終g_nCount1和g_nConnt2的值卻不相等。3.2.1臨界區(qū)對(duì)象1.為什么要線程同步?3.2.1臨界區(qū)對(duì)象1.為什么要線程同步?多線程同步要能保證在一個(gè)線程占有公共資源的時(shí)候,其他線程不會(huì)再占有這個(gè)資源。解決同步問(wèn)題,就要保證整個(gè)存取過(guò)程的獨(dú)占性。3.2.1臨界區(qū)對(duì)象1.為什么要線程同步?2.使用臨界區(qū)對(duì)象臨界區(qū)對(duì)象是定義在數(shù)據(jù)段中的一個(gè)CRITICAL_SECTION結(jié)構(gòu),Windows內(nèi)部使用這個(gè)結(jié)構(gòu)紀(jì)錄一些同步信息,確保在同一時(shí)間只有一個(gè)線程訪問(wèn)該數(shù)據(jù)段中的數(shù)據(jù)。2.使用臨界區(qū)對(duì)象臨界區(qū)對(duì)象是定義在數(shù)據(jù)段中的一個(gè)CRIT使用臨界區(qū)對(duì)象void
InitializeCriticalSection(LPCRITICAL_SECTION
lpCriticalSection
);
ParameterslpCriticalSection
[in]Pointertothecriticalsectionobject.初始化臨界區(qū)使用臨界區(qū)對(duì)象voidInitializeCritical使用臨界區(qū)對(duì)象void
EnterCriticalSection(LPCRITICAL_SECTION
lpCriticalSection
);
ParameterslpCriticalSection
[in]Pointertothecriticalsectionobject.申請(qǐng)進(jìn)入臨界區(qū)使用臨界區(qū)對(duì)象voidEnterCriticalSecti使用臨界區(qū)對(duì)象void
LeaveCriticalSection(LPCRITICAL_SECTION
lpCriticalSection
);
ParameterslpCriticalSection
[in]Pointertothecriticalsectionobject.將臨界區(qū)交還給Windows,離開臨界區(qū)使用臨界區(qū)對(duì)象voidLeaveCriticalSecti使用臨界區(qū)對(duì)象void
DeleteCriticalSection(LPCRITICAL_SECTION
lpCriticalSection
);
ParameterslpCriticalSection
[in]Pointertothecriticalsectionobject.整個(gè)程序不再使用臨界區(qū)的時(shí)候,將臨界區(qū)刪除使用臨界區(qū)對(duì)象voidDeleteCriticalSect使用臨界區(qū)對(duì)象使用方法說(shuō)明及程序例子03CriticalSection臨界區(qū)對(duì)象能夠很好的保護(hù)共享數(shù)據(jù),但是它不能夠用于進(jìn)程之間資源的鎖定,因?yàn)樗皇莾?nèi)核對(duì)象,如果要在進(jìn)程間維持線程的同步,可以使用事件內(nèi)核對(duì)象。使用臨界區(qū)對(duì)象使用方法說(shuō)明及程序例子03CriticalSe3.2.2互鎖函數(shù)互鎖函數(shù)為同步訪問(wèn)多線程共享變量提供了一個(gè)簡(jiǎn)單的機(jī)制。如果變量在共享內(nèi)存,不同進(jìn)程的線程也可以使用此機(jī)制?;ユi函數(shù)包括:InterlockedIncrementInterlockedDecrementInterlockedExchangeAddInterlockedExchangePointer3.2.2互鎖函數(shù)互鎖函數(shù)為同步訪問(wèn)多線程共享變量提供了一互鎖函數(shù)TheInterlockedIncrementfunctionincrements(increasesbyone)thevalueofthespecified32-bitvariableandcheckstheresultingvalue.Thefunctionpreventsmorethanonethreadfromusingthesamevariablesimultaneously.程序例子03InterlockDemo互鎖函數(shù)TheInterlockedIncrementfwhile(g_bContinue) { ::InterlockedIncrement((long*)&g_nCount1); ::InterlockedIncrement((long*)&g_nCount2); }在主線程中等待子線程的結(jié)束,子線程的結(jié)束條件是g_bContinue=false,這就保證了在一個(gè)子線程中,g_nCount1和g_nCount2執(zhí)行了相同多次。產(chǎn)生不一致的唯一原因是加1的操作被打斷while(g_bContinue)3.2.3事件內(nèi)核對(duì)象事件內(nèi)核對(duì)象主要用于線程間通信(同步就是一種簡(jiǎn)單的通信,指通信的數(shù)據(jù)量少)因?yàn)樗且粋€(gè)內(nèi)核對(duì)象,所以可以跨進(jìn)程使用,依靠通信,使各線程的工作協(xié)調(diào)進(jìn)行,達(dá)到同步的目的。事件內(nèi)核對(duì)象包括3個(gè)成員nUsageCount(使用計(jì)數(shù))bManualReset(是否人工重置)bSignaled(是否受信)3.2.3事件內(nèi)核對(duì)象事件內(nèi)核對(duì)象主要用于線程間通信(同步事件內(nèi)核對(duì)象使用WaitForSingleObject來(lái)判斷事件內(nèi)核對(duì)象是否受信,來(lái)達(dá)到通信的目的。使用CreateEvent函數(shù)創(chuàng)建事件對(duì)象。HANDLE
CreateEvent(
LPSECURITY_ATTRIBUTES
lpEventAttributes,安全屬性
BOOL
bManualReset,是否手動(dòng)重置
BOOL
bInitialState,初始狀態(tài)
LPTSTR
lpName
);
事件對(duì)象名稱事件內(nèi)核對(duì)象使用WaitForSingleObject來(lái)判斷事件內(nèi)核對(duì)象設(shè)置事件對(duì)象名稱是為了在其他地方(如:其他進(jìn)程的線程中)使用OpenEvent或者CreateEvent獲得此內(nèi)核對(duì)象句柄。HANDLEOpenEvent(DWORDdwDesiredAccess,訪問(wèn)權(quán)限
BOOLbInheritHandle,句柄是否被繼承
LPCTSTRlpName);
事件對(duì)象名稱事件內(nèi)核對(duì)象設(shè)置事件對(duì)象名稱是為了在其他地方(如:其他進(jìn)程的事件內(nèi)核對(duì)象BOOL
SetEvent(
HANDLE
hEvent
);
將事件對(duì)象狀態(tài)設(shè)置為“受信”BOOL
ResetEvent(HANDLEhEvent
);
將事件對(duì)象狀態(tài)設(shè)置為“未受信”程序例子事件內(nèi)核對(duì)象BOOLSetEvent(HANDLEhE事件內(nèi)核對(duì)象說(shuō)明當(dāng)一個(gè)自動(dòng)重置的事件對(duì)象受信以后,windows僅允許一個(gè)等待在該事件上的線程變?yōu)榭烧{(diào)度狀態(tài),然后就自動(dòng)重置此事件對(duì)象為未受信狀態(tài)。(如果使用setevent,則上述動(dòng)作是緊接著setevent進(jìn)行,然后才執(zhí)行setevent后面的代碼)當(dāng)一個(gè)人工重置事件對(duì)象受信后,所有等待在該對(duì)象上的線程都變?yōu)榭烧{(diào)度狀態(tài)。事件內(nèi)核對(duì)象說(shuō)明當(dāng)一個(gè)自動(dòng)重置的事件對(duì)象受信以后,windo線程同步問(wèn)題實(shí)例問(wèn)題描述:**********************************
*父親放蘋果,兒子吃蘋果,母親放香蕉,女兒吃香蕉
*在一個(gè)盤子之中只能放一樣水果,蘋果或香蕉
**********************************創(chuàng)建4個(gè)線程,分別代表父親、兒子、母親和女兒。主線程做初始化和收尾工作線程同步問(wèn)題實(shí)例問(wèn)題描述://放蘋果
UINTWINAPIPutAppleThread(PVOIDpvParam)
{
for(inti=0;i<10;i++)
{
WaitForSingleObject(g_dish,INFINITE);
WaitForSingleObject(g_putApple,INFINITE);
cout<<"putapple!\n";
SetEvent(g_eatApple);
Sleep(5);
}
return0;
}//放蘋果
UINTWINAPIPutAppleThre//放香蕉
UINTWINAPIPutBananaThread(PVOIDpvParam)
{
for(inti=0;i<10;i++)
{
WaitForSingleObject(g_dish,INFINITE);
WaitForSingleObject(g_putBanana,INFINITE);
cout<<"putbanana!\n";
SetEvent(g_eatBanana);
Sleep(5);
}
return0;
}//放香蕉
UINTWINAPIPutBananaThr//吃蘋果
UINTWINAPIEatAppleThread(PVOIDpvParam)
{
for(inti=0;i<10;i++)
{
WaitForSingleObject(g_eatApple,INFINITE);
cout<<"eatapple!\n";
SetEvent(g_putApple);
SetEvent(g_dish);;
}
return0;
}//吃蘋果
UINTWINAPIEatAppleThre//吃香蕉
UINTWINAPIEatBananaThread(PVOIDpvParam)
{
for(inti=0;i<10;i++)
{
WaitForSingleObject(g_eatBanana,INFINITE);
cout<<"eatbanana!\n";
SetEvent(g_putBanana);
SetEvent(g_dish);
}
return0;
}//吃香蕉
UINTWINAPIEatBananaThrintmain()
{
g_putApple=CreateEvent(NULL,FALSE,TRUE,NULL);
g_putBanana=CreateEvent(NULL,FALSE,TRUE,NULL);
g_eatApple=CreateEvent(NULL,FALSE,FALSE,NULL);
g_eatBanana=CreateEvent(NULL,FALSE,FALSE,NULL);
g_dish=CreateEvent(NULL,FALSE,TRUE,NULL);
HANDLEhThread[4];
intx;
hThread[0]=(HANDLE)_beginthreadex(NULL,0,PutAppleThread,(void*)&x,0,NULL);
hThread[1]=(HANDLE)_beginthreadex(NULL,0,PutBananaThread,(void*)&x,0,NULL);
hThread[2]=(HANDLE)_beginthreadex(NULL,0,EatAppleThread,(void*)&x,0,NULL);
hThread[3]=(HANDLE)_beginthreadex(NULL,0,EatBananaThread,(void*)&x,0,NULL);
charch;
cin>>ch;
return0;
}intmain()
{
g_putApple3.2.6線程局部存儲(chǔ)(TLS)線程局部存儲(chǔ)(thread-localstorage,TLS)是一個(gè)使用很方便的存儲(chǔ)線程局部數(shù)據(jù)的系統(tǒng)。利用TLS機(jī)制可以為進(jìn)程中所有的線程關(guān)聯(lián)若干個(gè)數(shù)據(jù),各個(gè)線程通過(guò)由TLS分配的全局索引來(lái)訪問(wèn)與自己關(guān)聯(lián)的數(shù)據(jù)。這樣,每個(gè)線程都可以有線程局部的靜態(tài)存儲(chǔ)數(shù)據(jù)。3.2.6線程局部存儲(chǔ)(TLS)線程局部存儲(chǔ)(thread線程局部存儲(chǔ)(TLS)線程局部存儲(chǔ)(TLS)線程局部存儲(chǔ)(TLS)動(dòng)態(tài)使用TLS的典型步驟如下。(1)主線程調(diào)用TlsAlloc函數(shù)為線程局部存儲(chǔ)分配索引,函數(shù)原型為:
DWORDTlsAlloc(void);
//返回一個(gè)TLS索引線程局部存儲(chǔ)(TLS)動(dòng)態(tài)使用TLS的典型步驟如下。線程局部存儲(chǔ)(TLS)
系統(tǒng)為每一個(gè)進(jìn)程都維護(hù)著一個(gè)長(zhǎng)度為TLS_MINIMUM_AVAILABLE的位數(shù)組,TlsAlloc的返回值就是數(shù)組的一個(gè)下標(biāo)(索引)。這個(gè)位數(shù)組的惟一用途就是記憶哪一個(gè)下標(biāo)在使用中。初始狀態(tài)下,此位數(shù)組成員的值都是FREE,表示未被使用。當(dāng)調(diào)用TlsAlloc的時(shí)候,系統(tǒng)會(huì)挨個(gè)檢查這個(gè)數(shù)組中成員的值,直到找到一個(gè)值為FREE的成員。把找到的成員的值由FREE改為INUSE后,TlsAlloc函數(shù)返回該成員的索引。如果不能找到一個(gè)值為FREE的成員,TlsAlloc函數(shù)就返回TLS_OUT_OF_INDEXES(在WinBase.h文件中定義為-1),意味著失敗。線程局部存儲(chǔ)(TLS)系統(tǒng)為每一個(gè)進(jìn)程都維護(hù)線程局部存儲(chǔ)(TLS)(2)每個(gè)線程調(diào)用TlsSetValue和TlsGetValue設(shè)置或讀取線程數(shù)組中的值,函數(shù)原型為:BOOLTlsSetValue(DWORDdwTlsIndex,
//TLS索引
LPVOIDlpTlsValue
//要設(shè)置的值
);LPVOIDTlsGetValue(DWORDdwTlsIndex);
//TLS索引線程局部存儲(chǔ)(TLS)(2)每個(gè)線程調(diào)用TlsSetValu線程局部存儲(chǔ)(TLS)TlsSetValue和TlsGetValue分別用于設(shè)置和取得線程數(shù)組中的特定成員的值,而它們使用的索引就是TlsAlloc函數(shù)的返回值。這就充分說(shuō)明了進(jìn)程中惟一的位數(shù)組和各線程數(shù)組的關(guān)系。例如,TlsAlloc返回3,那就說(shuō)明索引3被此進(jìn)程中的每一個(gè)正在運(yùn)行的和以后要被創(chuàng)建的線程保存起來(lái),用以訪問(wèn)各自線程數(shù)組中對(duì)應(yīng)的成員的值。線程局部存儲(chǔ)(TLS)TlsSetValue和T線程局部存儲(chǔ)(TLS)(3)主線程調(diào)用TlsFree釋放局部存儲(chǔ)索引。函數(shù)的惟一參數(shù)是TlsAlloc返回的索引。利用TLS可以給特定的線程關(guān)聯(lián)一個(gè)數(shù)據(jù)。比如下面的例子將每個(gè)線程的創(chuàng)建時(shí)間與該線程關(guān)聯(lián)了起來(lái),這樣,在線程終止的時(shí)候就可以得到線程的生命周期線程局部存儲(chǔ)(TLS)(3)主線程調(diào)用TlsFree釋放局部線程局部存儲(chǔ)(TLS)程序例子線程局部存儲(chǔ)(TLS)程序例子[實(shí)例]多線程文件搜索器structCDirectoryNode:publicCNoTrackObject{ CDirectoryNode*pNext; //CTypedSimpleList類模板要使用此成員,指向下一個(gè)節(jié)點(diǎn)的指針
charszDir[MAX_PATH]; //要查找的目錄};選擇從CNoTrackObject類繼承主要是為方便。當(dāng)創(chuàng)建對(duì)象時(shí),CNoTrackObject類中重載版本的operatornew會(huì)自動(dòng)將對(duì)象里各成員的值初始化為0。[實(shí)例]多線程文件搜索器structCDirectoryNclassCRapidFinder{public: CRapidFinder(intnMaxThread); virtual~CRapidFinder(); BOOLCheckFile(LPCTSTRlpszFileName); intm_nResultCount; //結(jié)果數(shù)目
intm_nThreadCount; //活動(dòng)線程數(shù)目
CTypedSimpleList<CDirectoryNode*>m_listDir;//
目錄列表
CRITICAL_SECTIONm_cs; //關(guān)鍵代碼段
constintm_nMaxThread; //最大線程數(shù)目
charm_szMatchName[MAX_PATH]; //要搜索的文件
HANDLEm_hDirEvent; //向m_listDir中添加新的目 錄后置位(受信)
HANDLEm_hExitEvent; //各搜索線程將要退出時(shí)置位 (受信)};classCRapidFinderAfxBeginThreadAfxBeginThreadcreatesanewCWinThreadobject,callsitsCreateThreadfunctiontostartexecutingthethread,andreturnsapointertothethread沒(méi)有返回線程句柄。CWinThread*
AfxBeginThread(
AFX_THREADPROC
pfnThreadProc,
LPVOID
pParam,
int
nPriority
=
THREAD_PRIORITY_NORMAL,
UINT
nStackSize
=
0,
DWORD
dwCreateFlags
=
0,
LPSECURITY_ATTRIBUTES
lpSecurityAttrs
=
NULL
);
AfxBeginThreadAfxBeginThreadc第3章Windows程序的執(zhí)行單元——線程第3章Windows程序的執(zhí)行單元——線程3.1多線程線程的創(chuàng)建線程內(nèi)核對(duì)象線程的終止線程的優(yōu)先級(jí)C/C++運(yùn)行期庫(kù)3.1多線程線程的創(chuàng)建線程的創(chuàng)建多線程并發(fā)執(zhí)行,os為其輪流分配cpu時(shí)間片一般情況,主線程接受用戶輸入,顯示運(yùn)行結(jié)果;新創(chuàng)建的線程來(lái)處理長(zhǎng)時(shí)間的操作,如讀寫文件、訪問(wèn)網(wǎng)絡(luò)等,這樣即便程序忙于繁重的工作也可以由專門的線程響應(yīng)用戶命令每個(gè)線程必須擁有入口點(diǎn)函數(shù),主線程的為main。輔助線程入口點(diǎn)函數(shù)稱為線程函數(shù),定義如下:DWORDWINAPIThreadProc(LPVOIDlpParam);
函數(shù)名稱ThreadProc可以是任意的線程的創(chuàng)建多線程并發(fā)執(zhí)行,os為其輪流分配cpu時(shí)間片線程的創(chuàng)建#defineWINAPI_stdcall;_stdcall是新標(biāo)準(zhǔn)c/c++調(diào)用方法,與標(biāo)準(zhǔn)c調(diào)用_cdecl相比,參數(shù)進(jìn)棧次序相同,從右到左,但_stdcall采用自動(dòng)清棧方式,而_cdecl采用手工清棧方式。由windows操作系統(tǒng)調(diào)用的函數(shù)(回調(diào)函數(shù))必須聲明為_stdcall沒(méi)有顯示說(shuō)明的話,為_cdecl調(diào)用方式線程的創(chuàng)建#defineWINAPI_stdcall;線程的創(chuàng)建創(chuàng)建新線程用CreateThreadHANDLE
CreateThread(
LPSECURITY_ATTRIBUTES
lpsa,DWORD
cbStack,LPTHREAD_START_ROUTINE
lpStartAddr,LPVOID
lpvThreadParam,DWORD
fdwCreate, LPDWORD
lpIDThread
);
線程的創(chuàng)建創(chuàng)建新線程用CreateThread線程的創(chuàng)建lpsa
[in]Ignored.MustbeNULL.指定線程安全屬性cbStack
[in]指定線程堆棧大小,NULL為默認(rèn)大小lpStartAddr
[in]線程函數(shù)起始地址lpvThreadParam
[in]Longpointertoasingle32-bitparametervaluepassedtothethread.fdwCreate
[in]Specifiesflagsthatcontrolthecreationofthethread.0表示線程創(chuàng)建后立即運(yùn)行l(wèi)pIDThread
[out]Longpointertoa32-bitvariablethatreceivesthethreadidentifier.IfthisparameterisNULL,thethreadidentifierisnotreturned.線程的創(chuàng)建lpsaWaitForSingleObjectDWORD
WaitForSingleObject(HANDLE
hHandle,DWORD
dwMilliseconds
);
Thisfunctionreturnswhenthespecifiedobjectisinthesignaledstate(受信狀態(tài))orwhenthetime-outintervalelapses.該函數(shù)用于等待指定的對(duì)象(hHandle)變成受信狀態(tài)。 說(shuō)明:在例03ThreadDemo工程中,用于等待輔助線程對(duì)應(yīng)的函數(shù)ThreadProc()執(zhí)行完成。調(diào)用該函數(shù)將阻塞主線程。一個(gè)可執(zhí)行對(duì)象有兩種狀態(tài):未受信、受信。線程對(duì)象只有當(dāng)線程結(jié)束才為受信態(tài)。WaitForSingleObjectDWORDWaitFWaitForSingleObjecthHandle
[in]Handletotheobject.Foralistoftheobjecttypeswhosehandlescanbespecified,seetheRemarkssection.dwMilliseconds
[in]Specifiesthetime-outinterval,inmilliseconds.Thefunctionreturnsiftheintervalelapses,eveniftheobject'sstateisnonsignaled.IfdwMillisecondsiszero,thefunctionteststheobject'sstateandreturnsimmediately.IfdwMillisecondsisINFINITE,thefunction'stime-outintervalneverelapses.WaitForSingleObjecthHandle線程的創(chuàng)建例子程序線程的創(chuàng)建例子程序3.1.2線程內(nèi)核對(duì)象線程內(nèi)核對(duì)象是一個(gè)包含了線程狀態(tài)信息的數(shù)據(jù)結(jié)構(gòu)。每次對(duì)CreateThread的成功調(diào)用,系統(tǒng)都會(huì)在內(nèi)部為新的線程分配一個(gè)內(nèi)核對(duì)象。系統(tǒng)對(duì)線程的管理是依靠訪問(wèn)線程內(nèi)核對(duì)象來(lái)實(shí)現(xiàn)的。1.線程上下文CONTEXT反映該線程上次運(yùn)行時(shí)CPU寄存器的狀態(tài)。3.1.2線程內(nèi)核對(duì)象線程內(nèi)核對(duì)象是一個(gè)包含了線程狀態(tài)信息2.線程創(chuàng)建例子中使用計(jì)數(shù)調(diào)用CreateThread后,使用計(jì)數(shù)=2,線程函數(shù)返回,系統(tǒng)將使使用計(jì)數(shù)減少1,即使用計(jì)數(shù)=1,接下來(lái)又調(diào)用CloseHandle使使用計(jì)數(shù)減1,即最后使用計(jì)數(shù)=0,該內(nèi)存空間被收回。2.線程創(chuàng)建例子中使用計(jì)數(shù)調(diào)用CreateThread后,CONTEXT(上下文,即寄存器的狀態(tài)),恢復(fù)現(xiàn)場(chǎng)必須使用使用計(jì)數(shù)(2):CreateThread返回句柄,相當(dāng)于打開一次內(nèi)核對(duì)象,促使該值+1,所以初始值=2;另外,OpenThread使該值+1,GetCurrentThread不會(huì)改變?cè)撝禃和4螖?shù)(1):1表示處于暫停狀態(tài),這樣就不會(huì)被調(diào)度到CPU中,給CreateThread時(shí)間對(duì)線程進(jìn)行初始化。初始化之后,如果未傳遞CREATE_SUSPENDED(掛起)標(biāo)志,暫停次數(shù)=0,該線程處于可調(diào)度狀態(tài)。喚醒用ResumeThread(),該函數(shù)使暫停次數(shù)-1,掛起用SuspendThread(),該函數(shù)使暫停次數(shù)+1,一個(gè)線程可以被掛起若干次,這就需要喚醒同樣次數(shù)才能使暫停次數(shù)=0,才能處于可調(diào)度狀態(tài),大約每隔20ms,進(jìn)行一次時(shí)間片輪轉(zhuǎn),os選擇新線程,將其上下文裝入cpu寄存器,組織起運(yùn)行。退出代碼(STILL_ALIVE):即線程函數(shù)的返回值,可以用GetExitCodeThread得到線程退出代碼,所以可以當(dāng)作自定義的返回值來(lái)表示線程的執(zhí)行結(jié)果。是否受信(FALSE):只有當(dāng)線程結(jié)束時(shí),該值才為TRUE…CONTEXT(上下文,即寄存器的狀態(tài)),恢復(fù)現(xiàn)場(chǎng)必須使用使3.1.3線程的終止線程終止的4種方法線程函數(shù)自然退出ExitThreadTerminateThread造成無(wú)法作清除工作,ExitProcess不提倡例子程序02ExitThread3.1.3線程的終止線程終止的4種方法3.1.4線程的優(yōu)先級(jí)每個(gè)線程被賦予一個(gè)優(yōu)先級(jí)號(hào),0——31,0最低,31最高,調(diào)度時(shí)選擇最高的,并采用搶占式優(yōu)先調(diào)度算法。eg:IEexplor的線程優(yōu)先級(jí)就很高。設(shè)置優(yōu)先級(jí)用SetThreadPriority()。BOOL
SetThreadPriority(HANDLE
hThread,int
nPriority
);
3.1.4線程的優(yōu)先級(jí)每個(gè)線程被賦予一個(gè)優(yōu)先級(jí)號(hào),0——3THREAD_PRIORITY_TIME_CRITICAL實(shí)時(shí)THREAD_PRIORITY_HIGHEST最高THREAD_PRIORITY_ABOVE_NORMAL高于正常THREAD_PRIORITY_NORMAL正常THREAD_PRIORITY_BELOW_NORMAL低于正常THREAD_PRIORITY_LOWEST最低THREAD_PRIORITY_ABOVE_IDLE高于最低THREAD_PRIORITY_IDLE空閑THREAD_PRIORITY_TIME_CRITICAL線程的優(yōu)先級(jí)例子程序線程的優(yōu)先級(jí)例子程序3.1.5C/C++運(yùn)行期庫(kù)在實(shí)際的開發(fā)過(guò)程中,一般使用c/c++運(yùn)行期函數(shù)_beginthreadx代替CreateThread函數(shù)。_beginthreadx首先申請(qǐng)一些用于線程同步的變量,然后調(diào)用CreateThreadVc++默認(rèn)的c/c++運(yùn)行期庫(kù)不支持_beginthreadx,需要設(shè)置”Project/settings/c/c++/codegeneration/…./選中multithreadDLL”即可。需要#include<process.h>同樣,使用_endthreadex代替ExitThread。該函數(shù)首先釋放用于線程同步的變量,再調(diào)用ExitThread3.1.5C/C++運(yùn)行期庫(kù)在實(shí)際的開發(fā)過(guò)程中,一般使用c3.2線程同步同步可以保證在一個(gè)時(shí)間內(nèi)只有一個(gè)線程對(duì)某個(gè)共享資源有控制權(quán)。臨界區(qū)對(duì)象事件內(nèi)核對(duì)象線程局部存儲(chǔ)(TLS)3.2線程同步同步可以保證在一個(gè)時(shí)間內(nèi)只有一個(gè)線程對(duì)某個(gè)共3.2線程同步解決同步問(wèn)題的方法:臨界區(qū)對(duì)象:線程獨(dú)占,等待的線程掛起,不可調(diào)度互鎖函數(shù):單一變量同步問(wèn)題事件內(nèi)核對(duì)象:是否”受信”,通知信號(hào)量?jī)?nèi)核對(duì)象:信號(hào)量計(jì)數(shù),多個(gè)線程共享,用于Socket(套接字)程序中線程同步互斥內(nèi)核對(duì)象:線程獨(dú)占,等待的線程可調(diào)度,用于保護(hù)內(nèi)存3.2線程同步解決同步問(wèn)題的方法:3.2.1臨界區(qū)對(duì)象1.為什么要線程同步?當(dāng)多個(gè)線程在同一個(gè)進(jìn)程中執(zhí)行時(shí),可能有不止一個(gè)線程同時(shí)執(zhí)行同一段代碼,訪問(wèn)同一段內(nèi)存中的數(shù)據(jù)。線程同步產(chǎn)生的問(wèn)題——一個(gè)錯(cuò)誤的例子03ConntErr→線程函數(shù)ThreadFunc同時(shí)增加全局變量g_nCount1和g_nConnt2的計(jì)數(shù),原則上兩個(gè)變量的值應(yīng)該相等,但由于是兩個(gè)線程同時(shí)訪問(wèn)這兩個(gè)全局變量,最終g_nCount1和g_nConnt2的值卻不相等。3.2.1臨界區(qū)對(duì)象1.為什么要線程同步?3.2.1臨界區(qū)對(duì)象1.為什么要線程同步?多線程同步要能保證在一個(gè)線程占有公共資源的時(shí)候,其他線程不會(huì)再占有這個(gè)資源。解決同步問(wèn)題,就要保證整個(gè)存取過(guò)程的獨(dú)占性。3.2.1臨界區(qū)對(duì)象1.為什么要線程同步?2.使用臨界區(qū)對(duì)象臨界區(qū)對(duì)象是定義在數(shù)據(jù)段中的一個(gè)CRITICAL_SECTION結(jié)構(gòu),Windows內(nèi)部使用這個(gè)結(jié)構(gòu)紀(jì)錄一些同步信息,確保在同一時(shí)間只有一個(gè)線程訪問(wèn)該數(shù)據(jù)段中的數(shù)據(jù)。2.使用臨界區(qū)對(duì)象臨界區(qū)對(duì)象是定義在數(shù)據(jù)段中的一個(gè)CRIT使用臨界區(qū)對(duì)象void
InitializeCriticalSection(LPCRITICAL_SECTION
lpCriticalSection
);
ParameterslpCriticalSection
[in]Pointertothecriticalsectionobject.初始化臨界區(qū)使用臨界區(qū)對(duì)象voidInitializeCritical使用臨界區(qū)對(duì)象void
EnterCriticalSection(LPCRITICAL_SECTION
lpCriticalSection
);
ParameterslpCriticalSection
[in]Pointertothecriticalsectionobject.申請(qǐng)進(jìn)入臨界區(qū)使用臨界區(qū)對(duì)象voidEnterCriticalSecti使用臨界區(qū)對(duì)象void
LeaveCriticalSection(LPCRITICAL_SECTION
lpCriticalSection
);
ParameterslpCriticalSection
[in]Pointertothecriticalsectionobject.將臨界區(qū)交還給Windows,離開臨界區(qū)使用臨界區(qū)對(duì)象voidLeaveCriticalSecti使用臨界區(qū)對(duì)象void
DeleteCriticalSection(LPCRITICAL_SECTION
lpCriticalSection
);
ParameterslpCriticalSection
[in]Pointertothecriticalsectionobject.整個(gè)程序不再使用臨界區(qū)的時(shí)候,將臨界區(qū)刪除使用臨界區(qū)對(duì)象voidDeleteCriticalSect使用臨界區(qū)對(duì)象使用方法說(shuō)明及程序例子03CriticalSection臨界區(qū)對(duì)象能夠很好的保護(hù)共享數(shù)據(jù),但是它不能夠用于進(jìn)程之間資源的鎖定,因?yàn)樗皇莾?nèi)核對(duì)象,如果要在進(jìn)程間維持線程的同步,可以使用事件內(nèi)核對(duì)象。使用臨界區(qū)對(duì)象使用方法說(shuō)明及程序例子03CriticalSe3.2.2互鎖函數(shù)互鎖函數(shù)為同步訪問(wèn)多線程共享變量提供了一個(gè)簡(jiǎn)單的機(jī)制。如果變量在共享內(nèi)存,不同進(jìn)程的線程也可以使用此機(jī)制?;ユi函數(shù)包括:InterlockedIncrementInterlockedDecrementInterlockedExchangeAddInterlockedExchangePointer3.2.2互鎖函數(shù)互鎖函數(shù)為同步訪問(wèn)多線程共享變量提供了一互鎖函數(shù)TheInterlockedIncrementfunctionincrements(increasesbyone)thevalueofthespecified32-bitvariableandcheckstheresultingvalue.Thefunctionpreventsmorethanonethreadfromusingthesamevariablesimultaneously.程序例子03InterlockDemo互鎖函數(shù)TheInterlockedIncrementfwhile(g_bContinue) { ::InterlockedIncrement((long*)&g_nCount1); ::InterlockedIncrement((long*)&g_nCount2); }在主線程中等待子線程的結(jié)束,子線程的結(jié)束條件是g_bContinue=false,這就保證了在一個(gè)子線程中,g_nCount1和g_nCount2執(zhí)行了相同多次。產(chǎn)生不一致的唯一原因是加1的操作被打斷while(g_bContinue)3.2.3事件內(nèi)核對(duì)象事件內(nèi)核對(duì)象主要用于線程間通信(同步就是一種簡(jiǎn)單的通信,指通信的數(shù)據(jù)量少)因?yàn)樗且粋€(gè)內(nèi)核對(duì)象,所以可以跨進(jìn)程使用,依靠通信,使各線程的工作協(xié)調(diào)進(jìn)行,達(dá)到同步的目的。事件內(nèi)核對(duì)象包括3個(gè)成員nUsageCount(使用計(jì)數(shù))bManualReset(是否人工重置)bSignaled(是否受信)3.2.3事件內(nèi)核對(duì)象事件內(nèi)核對(duì)象主要用于線程間通信(同步事件內(nèi)核對(duì)象使用WaitForSingleObject來(lái)判斷事件內(nèi)核對(duì)象是否受信,來(lái)達(dá)到通信的目的。使用CreateEvent函數(shù)創(chuàng)建事件對(duì)象。HANDLE
CreateEvent(
LPSECURITY_ATTRIBUTES
lpEventAttributes,安全屬性
BOOL
bManualReset,是否手動(dòng)重置
BOOL
bInitialState,初始狀態(tài)
LPTSTR
lpName
);
事件對(duì)象名稱事件內(nèi)核對(duì)象使用WaitForSingleObject來(lái)判斷事件內(nèi)核對(duì)象設(shè)置事件對(duì)象名稱是為了在其他地方(如:其他進(jìn)程的線程中)使用OpenEvent或者CreateEvent獲得此內(nèi)核對(duì)象句柄。HANDLEOpenEvent(DWORDdwDesiredAccess,訪問(wèn)權(quán)限
BOOLbInheritHandle,句柄是否被繼承
LPCTSTRlpName);
事件對(duì)象名稱事件內(nèi)核對(duì)象設(shè)置事件對(duì)象名稱是為了在其他地方(如:其他進(jìn)程的事件內(nèi)核對(duì)象BOOL
SetEvent(
HANDLE
hEvent
);
將事件對(duì)象狀態(tài)設(shè)置為“受信”BOOL
ResetEvent(HANDLEhEvent
);
將事件對(duì)象狀態(tài)設(shè)置為“未受信”程序例子事件內(nèi)核對(duì)象BOOLSetEvent(HANDLEhE事件內(nèi)核對(duì)象說(shuō)明當(dāng)一個(gè)自動(dòng)重置的事件對(duì)象受信以后,windows僅允許一個(gè)等待在該事件上的線程變?yōu)榭烧{(diào)度狀態(tài),然后就自動(dòng)重置此事件對(duì)象為未受信狀態(tài)。(如果使用setevent,則上述動(dòng)作是緊接著setevent進(jìn)行,然后才執(zhí)行setevent后面的代碼)當(dāng)一個(gè)人工重置事件對(duì)象受信后,所有等待在該對(duì)象上的線程都變?yōu)榭烧{(diào)度狀態(tài)。事件內(nèi)核對(duì)象說(shuō)明當(dāng)一個(gè)自動(dòng)重置的事件對(duì)象受信以后,windo線程同步問(wèn)題實(shí)例問(wèn)題描述:**********************************
*父親放蘋果,兒子吃蘋果,母親放香蕉,女兒吃香蕉
*在一個(gè)盤子之中只能放一樣水果,蘋果或香蕉
**********************************創(chuàng)建4個(gè)線程,分別代表父親、兒子、母親和女兒。主線程做初始化和收尾工作線程同步問(wèn)題實(shí)例問(wèn)題描述://放蘋果
UINTWINAPIPutAppleThread(PVOIDpvParam)
{
for(inti=0;i<10;i++)
{
WaitForSingleObject(g_dish,INFINITE);
WaitForSingleObject(g_putApple,INFINITE);
cout<<"putapple!\n";
SetEvent(g_eatApple);
Sleep(5);
}
return0;
}//放蘋果
UINTWINAPIPutAppleThre//放香蕉
UINTWINAPIPutBananaThread(PVOIDpvParam)
{
for(inti=0;i<10;i++)
{
WaitForSingleObject(g_dish,INFINITE);
WaitForSingleObject(g_putBanana,INFINITE);
cout<<"putbanana!\n";
SetEvent(g_eatBanana);
Sleep(5);
}
return0;
}//放香蕉
UINTWINAPIPutBananaThr//吃蘋果
UINTWINAPIEatAppleThread(PVOIDpvParam)
{
for(inti=0;i<10;i++)
{
WaitForSingleObject(g_eatApple,INFINITE);
cout<<"eatapple!\n";
SetEvent(g_putApple);
SetEvent(g_dish);;
}
return0;
}//吃蘋果
UINTWINAPIEatAppleThre//吃香蕉
UINTWINAPIEatBananaThread(PVOIDpvParam)
{
for(inti=0;i<10;i++)
{
WaitForSingleObject(g_eatBanana,INFINITE);
cout<<"eatbanana!\n";
SetEvent(g_putBanana);
SetEvent(g_dish);
}
return0;
}//吃香蕉
UINTWINAPIEatBananaThrintmain()
{
g_putApple=CreateEvent(NULL,FALSE,TRUE,NULL);
g_putBanana=CreateEvent(NULL,FALSE,TRUE,NULL);
g_eatApple=CreateEvent(NULL,FALSE,FALSE,NULL);
g_eatBanana=CreateEvent(NULL,FALSE,FALSE,NULL);
g_dish=CreateEvent(NULL,FALSE,TRUE,NULL);
HANDLEhThread[4];
intx;
hThread[0]=(HANDLE)_beginthreadex(NULL,0,PutAppleThread,(void*)&x,0,NULL);
hThread[1]=(HANDLE)_beginthreadex(NULL,0,PutBananaThread,(void*)&x,0,NULL);
hThread[2]=(HANDLE)_beginthreadex(NULL,0,EatAppleThread,(void*)&x,0,NULL);
hThread[3]=(HANDLE)_beginthreadex(NULL,0,EatBananaThread,(void*)&x,0,NULL);
charch;
cin>>ch;
return0;
}intmain()
{
g_putApple3.2.6線程局部存儲(chǔ)(TLS)線程局部存儲(chǔ)(thread-localstorage,TLS)是一個(gè)使用很方便的存儲(chǔ)線程局部數(shù)據(jù)的系統(tǒng)。利用TLS機(jī)制可以為進(jìn)程中所有的線程關(guān)聯(lián)若干個(gè)數(shù)據(jù),各個(gè)線程通過(guò)由TLS分配的全局索引來(lái)訪問(wèn)與自己關(guān)聯(lián)
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度技術(shù)合作項(xiàng)目終止及解除合同書
- 2025年度農(nóng)村水井承包合同與農(nóng)業(yè)灌溉用水權(quán)流轉(zhuǎn)及監(jiān)管協(xié)議
- 2025年度特殊年齡段勞動(dòng)者用工協(xié)議及權(quán)益保障
- 2025年度個(gè)體商戶勞動(dòng)合同(家政服務(wù)行業(yè)合作)
- 5G通信借款居間合同模板
- 2025年度分紅股收益確認(rèn)與分配協(xié)議
- 2025年度影視作品著作權(quán)許可及廣告植入合作合同
- 2025年度分手協(xié)議書模板:分手后共同債務(wù)承擔(dān)協(xié)議
- 2025年度房屋拆除與建筑垃圾清運(yùn)一體化服務(wù)合同
- 2025年度企業(yè)導(dǎo)師帶徒技能傳承服務(wù)協(xié)議
- (高清版)TDT 1056-2019 縣級(jí)國(guó)土資源調(diào)查生產(chǎn)成本定額
- 公司合作計(jì)劃書
- 2016-2023年南京信息職業(yè)技術(shù)學(xué)院高職單招(英語(yǔ)/數(shù)學(xué)/語(yǔ)文)筆試歷年參考題庫(kù)含答案解析
- 跨領(lǐng)域聯(lián)合診療(MDT)管理法規(guī)
- 光伏電站運(yùn)維安全風(fēng)險(xiǎn)管控清單
- 保安員考核評(píng)分標(biāo)準(zhǔn)與細(xì)則
- 四年級(jí)豎式計(jì)算大全100道
- 履行法定義務(wù)糾正違法行為的模板
- 越劇基本知識(shí)講座
- 崗位績(jī)效獎(jiǎng)勵(lì)制度
- JGT161-2016 無(wú)粘結(jié)預(yù)應(yīng)力鋼絞線
評(píng)論
0/150
提交評(píng)論