In t e r l o c k e d E x c h a n g e和I n t e r l o c k e d E x c h a n g e P o i n t e r能夠以原子操作方式用第二個參數(shù)中傳遞的值來取代第一個參數(shù)中傳遞的當(dāng)前值。如果是3 2位應(yīng)用程序,兩個函數(shù)都能用另一個3 2位值取代一個3 2位值。但是,如果是個6 4位應(yīng)用程序,那么I n t e r l o c k e d E x c h a n g e能夠取代一個3 2位值,而I n t e r l o c k e d E x c h a n g e P o i n t e r則取代6 4位值。兩個函數(shù)都返回原始值。當(dāng)實現(xiàn)一個循環(huán)鎖時,I n t e r l o c k e d E x c h a n g e是非常有用的:
// Global variable indicating whether a shared resource is in use or not
BOOL g_fResourceInUse = FALSE;
...
void Func1()
{
//Wait to access the resource.
while(InterlockedExchange(&g_fResourceInUse, TRUE) == TRUE)
Sleep(0);
//Access the resource.
...
//We no longer need to access the resource.
InterlockedExchange(&g_fResourceInUse, FALSE);
}
w h i l e循環(huán)是循環(huán)運行的,它將g _ f R e s o u r c e I n U s e中的值改為T R U E,并查看它的前一個值,以了解它是否是T R U E。如果這個值原先是FA L S E,那么該資源并沒有在使用,而是調(diào)用線程將它設(shè)置為在用狀態(tài)并退出該循環(huán)。如果前一個值是T R U E,那么資源正在被另一個線程使用,w h i l e循環(huán)將繼續(xù)循環(huán)運行。
如果另一個線程要執(zhí)行類似的代碼,它將在w h i l e循環(huán)中運行,直到g _ f R e s o u r c e I n U s e重新改為FA L S E。調(diào)用函數(shù)結(jié)尾處的I n t e r l o c k e d E x c h a n g e,可顯示應(yīng)該如何將g _ f R e s o u r c e I n U s e重新設(shè)置為FA L S E。
當(dāng)使用這個方法時必須格外小心,因為循環(huán)鎖會浪費C P U時間。C P U必須不斷地比較兩個值,直到一個值由于另一個線程而“奇妙地”改變?yōu)橹埂A硗猓摯a假定使用循環(huán)鎖的所有線程都以相同的優(yōu)先級等級運行。也可以把執(zhí)行循環(huán)鎖的線程的優(yōu)先級提高功能禁用(通過調(diào)用S e t P r o c e s s P r i o r i t y B o o s t或s e t T h r e a d P r i o r i t y B o o s t函數(shù)來實現(xiàn)之)
此外,應(yīng)該保證將循環(huán)鎖變量和循環(huán)鎖保護的數(shù)據(jù)維護在不同的高速緩存行中(本章后面部分介紹)。如果循環(huán)鎖變量與數(shù)據(jù)共享相同的高速緩存行,那么使用該資源的C P U將與試圖訪問該資源的任何C P U爭用高速緩存行。
應(yīng)該避免在單個C P U計算機上使用循環(huán)鎖。如果一個線程正在循環(huán)運行,它就會浪費前一個C P U時間,這將防止另一個線程修改該值。我在上面的w h i l e循環(huán)中使用了S l e e p ,從而在某種程度上解決了浪費C P U時間的問題。如果使用S l e e p,你可能想睡眠一個隨機時間量;每次請求訪問該資源均被拒絕時,你可能想進一步延長睡眠時間。這可以防止線程浪費C P U時間。根據(jù)情況,最好是全部刪除對S l e e p的調(diào)用。或者使用對S w i t c h To T h r e a d(Windows 98中沒有這個函數(shù))的調(diào)用來取代它。勇于試驗和不斷糾正錯誤,是學(xué)習(xí)的最好方法。
循環(huán)鎖假定,受保護的資源總是被訪問較短的時間。這使它能夠更加有效地循環(huán)運行,然后轉(zhuǎn)為內(nèi)核方式并進入等待狀態(tài)。許多編程人員循環(huán)運行一定的次數(shù)(比如4 0 0次),如果對資源的訪問仍然被拒絕,那么該線程就轉(zhuǎn)為內(nèi)核方式,在這種方式下,它要等待(不消耗C P U時間),直到該資源變?yōu)榭晒┦褂脼橹埂_@就是關(guān)鍵部分實現(xiàn)的方法。
循環(huán)鎖在多處理器計算機上非常有用,因為當(dāng)一個線程循環(huán)運行的時候,另一個線程可以在另一個C P U上運行。但是,即使在這種情況下,也必須小心。不應(yīng)該讓線程循環(huán)運行太長的時間,也不能浪費更多的C P U時間。本章后面將進一步介紹循環(huán)鎖。