国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
用戶方式中線程的同步
用戶方式中線程的同步 
1. 僅一條語句用不用考慮線程同步的問題? 
當(dāng)使用高級語言編程時,我們往往會認為一條語句是最小的原子訪問,CPU不會在這條語句中間運行其他的線程。這是錯誤的,因為即使非常簡單的一條高級語言的語句,經(jīng)編譯器編譯后也可能變成多行代碼由計算機來執(zhí)行。因此必須考慮線程同步的問題。任何線程都不應(yīng)該通過調(diào)用簡單的C語句來修改共享的變量。 
2. 互鎖函數(shù)有那些? 
(1) LONG   InterlockedExchangeAdd   (   LPLONG   Addend,   LONG   Increment   ); 
Addend為長整型變量的地址,Increment為想要在Addend指向的長整型變量上增加的數(shù)值(可以是負數(shù))。這個函數(shù)的主要作用是保證這個加操作為一個原子訪問。 
(2) LONG   InterlockedExchange(   LPLONG   Target,   LONG   Value   ); 
用第二個參數(shù)的值取代第一個參數(shù)指向的值。函數(shù)返回值為原始值。 
(3) PVOID   InterlockedExchangePointer(   PVOID   *Target,   PVOID   Value   ); 
用第二個參數(shù)的值取代第一個參數(shù)指向的值。函數(shù)返回值為原始值。 
(4) LONG   InterlockedCompareExchange(   
LPLONG   Destination,   LONG   Exchange,   LONG   Comperand     ); 
如果第三個參數(shù)與第一個參數(shù)指向的值相同,那么用第二個參數(shù)取代第一個參數(shù)指向的值。函數(shù)返回值為原始值。 
(5) PVOID   InterlockedCompareExchangePointer   ( 
PVOID   *Destination,   PVOID   Exchange,   PVOID   Comperand   ); 
如果第三個參數(shù)與第一個參數(shù)指向的值相同,那么用第二個參數(shù)取代第一個參數(shù)指向的值。函數(shù)返回值為原始值。 
3. 為什么單CPU的計算機不應(yīng)該使用循環(huán)鎖? 
舉例說明: 
BOOL   g_bResourceUse   =   FALSE; 
…… 
void   ThreadFunc1(     ) 

BOOL   bResourceUse   =   FALSE; 
while(   1   ) 

bResourceUse   =   InterlockedExchange(   &g_bResourceUse,   TRUE   ); 
if(   bResourceUse   ==   FALSE   ) 

break; 

Sleep(   0   ); 

…… 
…… 
…… 
InterlockedExchange(   &g_bResourceUse,   FALSE   ); 

首先循環(huán)鎖會浪費CPU時間。CPU必須不斷地比較兩個值,直到一個值由于另一個線程而“奇妙地”改變?yōu)橹埂6沂褂迷撗h(huán)鎖的線程都應(yīng)該為同一優(yōu)先級,并且應(yīng)當(dāng)使用SetProcessPriorityBoost函數(shù)或SetThreadPriorityBoost函數(shù)禁止線程優(yōu)先級的動態(tài)提高功能,否則優(yōu)先級較低的線程可能永遠不能被調(diào)用。 
4. 如何使用volatile聲明變量? 
如果是對共享資源的地址進行使用如&g_Resource那么可以不使用volatile,因為將一個變量地址傳遞給一個函數(shù)時,該函數(shù)必須從內(nèi)存讀取該值。優(yōu)化程序不會對它產(chǎn)生任何影響。如果直接使用變量,必須有一個volatile類型的限定詞。它告訴編譯器,變量可以被應(yīng)用程序本身以外的某個東西進行修改,這些東西包括操作系統(tǒng),硬件或同時執(zhí)行的線程等。volatile限定詞會告訴編譯器,不要對該變量進行任何優(yōu)化,并且總是重新加載來自該變量的內(nèi)存單元的值。否則編譯器會把變量的值存入CPU寄存器,每次對寄存器進行操作。線程就會進入一個無限循環(huán),永遠無法喚醒。 
5. 如何使用關(guān)鍵代碼段實現(xiàn)線程的同步? 
如果需要一小段代碼以原子操作的方式執(zhí)行,這時簡單的互鎖函數(shù)已不能滿足需要,必須使用關(guān)鍵代碼段來解決問題。不過使用關(guān)鍵代碼段時,很容易陷入死鎖狀態(tài),因為在等待進入關(guān)鍵代碼段時無法設(shè)定超時值。關(guān)鍵代碼段是通過對共享資源設(shè)置一個標(biāo)志來實現(xiàn)的,就像廁所門上的“有人/沒人”標(biāo)志一樣。這個標(biāo)志就是一個CRITICAL_SECTION變量。該變量在任何一個線程使用它之前應(yīng)當(dāng)進行初始化。初始化可以有兩種方法,使用InitializeCriticalSection函數(shù)和InitializeCriticalSectionAndSpinCount函數(shù)。然后在每個使用共享資源的線程函數(shù)的關(guān)鍵代碼段前使用EnterCriticalSection函數(shù)或者使用TryEnterCriticalSection函數(shù)。在關(guān)鍵代碼段使用之后調(diào)用LeaveCriticalSection函數(shù)。在所有的線程都不再使用該共享資源后應(yīng)當(dāng)調(diào)用DeleteCriticalSection函數(shù)來清除該標(biāo)志。舉例說明: 
const   int   MAX_TIMES   =   1000; 
int     g_intIndex   =   0; 
DWORD   g_dwTimes[MAX_TIMES]; 
CRITICAL_SECTION   g_cs; 

void   Init(     ) 

…… 
InitializeCriticalSection(   &g_cs   ); 
…… 


DWORD   WINAPI   FirstThread(   PVOID   lpParam   ) 

while   (   g_intIndex   <   MAX_TIMES   ) 

EnterCriticalSection(   &g_cs   ); 
g_dwTimes[g_intIndex]   =   GetTickCount(     ); 
g_intIndex++; 
LeaveCriticalSection(   &g_cs   ); 

return   0; 


DWORD   WINAPI   SecondThread(   PVOID   lpParam   ) 

while   (   g_intIndex   <   MAX_TIMES   ) 

EnterCriticalSection(   &g_cs   ); 
g_intIndex++; 
g_dwTimes[g_intIndex   -   1]   =   GetTickCount(     ); 
LeaveCriticalSection(   &g_cs   ); 

return   0; 


void   Close(     ) 

…… 
DeleteCriticalSection(   &g_cs   ); 
…… 

使用關(guān)鍵代碼段應(yīng)當(dāng)注意一些技巧: 
(1) 每個共享資源使用一個CRITICAL_SECTION變量。 
這樣在當(dāng)前線程占有一個資源時,另一個資源可以被其他線程占有。 
EnterCriticalSection(   &g_cs   ); 
for   (   intLoop   =   0;   intLoop   <   100;   intLoop++   ) 

g_intArray[intLoop]   =   0; 
g_uintArray[intLoop]   =   0; 

LeaveCriticalSection(   &g_cs   ); 
改為: 
EnterCriticalSection(   &g_csInt   ); 
for   (   intLoop   =   0;   intLoop   <   100;   intLoop++   ) 

g_intArray[intLoop]   =   0; 

LeaveCriticalSection(   &g_csInt   ); 
EnterCriticalSection(   &g_csUint   ); 
for   (   intLoop   =   0;   intLoop   <   100;   intLoop++   ) 

g_uintArray[intLoop]   =   0; 

LeaveCriticalSection(   &g_csUint   ); 
(2) 同時訪問多個資源,必須始終按照完全相同的順序請求對資源的訪問。 
這樣才能避免死鎖狀態(tài)產(chǎn)生。離開的順序沒有關(guān)系。 
Thread1: 
EnterCriticalSection(   &g_csInt   ); 
EnterCriticalSection(   &g_csUint   ); 
for   (   intLoop   =   0;   intLoop   <   100;   intLoop++   ) 

g_uintArray[intLoop]   =   g_intArray[intLoop]; 

LeaveCriticalSection(   &g_csInt   ); 
LeaveCriticalSection(   &g_csUint   ); 
Thread2: 
EnterCriticalSection(   &g_csUint   ); 
EnterCriticalSection(   &g_csInt   ); 
for   (   intLoop   =   0;   intLoop   <   100;   intLoop++   ) 

g_uintArray[intLoop]   =   g_intArray[intLoop]; 

LeaveCriticalSection(   &g_csInt   ); 
LeaveCriticalSection(   &g_csUint   ); 
改為: 
Thread1: 
EnterCriticalSection(   &g_csInt   ); 
EnterCriticalSection(   &g_csUint   ); 
for   (   intLoop   =   0;   intLoop   <   100;   intLoop++   ) 

g_uintArray[intLoop]   =   g_intArray[intLoop]; 

LeaveCriticalSection(   &g_csInt   ); 
LeaveCriticalSection(   &g_csUint   ); 
Thread2: 
EnterCriticalSection(   &g_csInt   ); 
EnterCriticalSection(   &g_csUint   ); 
for   (   intLoop   =   0;   intLoop   <   100;   intLoop++   ) 

g_uintArray[intLoop]   =   g_intArray[intLoop]; 

LeaveCriticalSection(   &g_csInt   ); 
LeaveCriticalSection(   &g_csUint   ); 
(3) 不要長時間運行關(guān)鍵代碼段。 
EnterCriticalSection(   &g_cs   ); 
SendMessage(   hWnd,   WM_SOMEMSG,   &g_s,   0   ); 
LeaveCriticalSection(   &g_cs   ); 
改為: 
EnterCriticalSection(   &g_cs   ); 
sTemp   =   g_s; 
LeaveCriticalSection(   &g_cs   ); 
SendMessage(   hWnd,   WM_SOMEMSG,   &sTemp,   0   ); 
6. InitializeCriticalSection/InitializeCriticalSectionAndSpinCount差別? 
InitializeCriticalSection函數(shù)的返回值為空并且不會創(chuàng)建事件內(nèi)核對象,比較節(jié)省系統(tǒng)資源,但是一旦發(fā)生兩個或多個線程爭用關(guān)鍵代碼段的情況,如果內(nèi)存不足,關(guān)鍵代碼段可能被爭用,同時系統(tǒng)可能無法創(chuàng)建必要的事件內(nèi)核對象。這時EnterCriticalSection函數(shù)將會產(chǎn)生一個EXCEPTION_INVALID_HANDLE異常。這個錯誤非常少見。如果想對這種情況有所準(zhǔn)備,可以有兩種選擇??梢允褂媒Y(jié)構(gòu)化異常處理方法來跟蹤錯誤。當(dāng)錯誤發(fā)生時,既可以不訪問關(guān)鍵代碼段保護的資源,也可以等待某些內(nèi)存變成可用狀態(tài),然后再次調(diào)用EnterCriticalSection函數(shù)。 
另一種選擇是使用InitializeCriticalSectionAndSpinCount,第二個參數(shù)dwSpinCount中,傳遞的是在使線程等待之前它試圖獲得資源時想要循環(huán)鎖循環(huán)迭代的次數(shù)。這個值可以是0至0x00FFFFFF之間的任何數(shù)字。如果在單處理器計算機上運行時調(diào)用該函數(shù),該參數(shù)被忽略,并且始終設(shè)置為0。使用InitializeCriticalSectionAndSpinCount函數(shù)創(chuàng)建關(guān)鍵代碼段,確保設(shè)置了dwSpinCount參數(shù)的高信息位。當(dāng)該函數(shù)發(fā)現(xiàn)高信息位已經(jīng)設(shè)置時,它就創(chuàng)建該事件內(nèi)核對象,并在初始化時將它與關(guān)鍵代碼段關(guān)聯(lián)起來。如果事件無法創(chuàng)建,該函數(shù)返回FALSE。可以更加妥善地處理代碼中的這個事件。如果事件創(chuàng)建成功,EnterCriticalSection將始終都能運行,并且決不會產(chǎn)生異常情況(如果總是預(yù)先分配事件內(nèi)核對象,就會浪費系統(tǒng)資源。只有當(dāng)代碼不能容許EnterCriticalSection運行失敗,或者有把握會出現(xiàn)爭用現(xiàn)象,或者預(yù)計進程將在內(nèi)存非常短缺的環(huán)境中運行時,才能預(yù)先分配事件內(nèi)核對象)。 
7. TryEnterCriticalSection和EnterCriticalSection的差別是什么? 
如果EnterCriticalSection將一個線程置于等待狀態(tài),那么該線程在很長時間內(nèi)就不能再次被調(diào)度。實際上,在編寫得不好的應(yīng)用程序中,該線程永遠不會再次被賦予CPU時間。TryEnterCriticalSection函數(shù)決不允許調(diào)用線程進入等待狀態(tài)。它的返回值能夠指明調(diào)用線程是否能夠獲得對資源的訪問權(quán)。TryEnterCriticalSection發(fā)現(xiàn)該資源已經(jīng)被另一個線程訪問,它就返回FALSE。在其他所有情況下,它均返回TRUE。運用這個函數(shù),線程能夠迅速查看它是否可以訪問某個共享資源,如果不能訪問,那么它可以繼續(xù)執(zhí)行某些其他操作,而不必進行等待。如果TryEnterCriticalSection函數(shù)確實返回了TRUE,那么CRITICAL_SECTION的成員變量已經(jīng)更新。Windows98沒有可以使用的TryEnterCriticalSection函數(shù)的實現(xiàn)代碼。
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
線程的基礎(chǔ)知識
深入淺出Win32多線程程序設(shè)計之線程通信
Mutex和Critical_Section都是主要用于限制多線程
win32多線程(2)
對CRITICAL_SECTION理解的總結(jié) - 雨巷叮當(dāng)?shù)娜罩?- 網(wǎng)易博客
臨界區(qū)實現(xiàn)線程同步互斥
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服