InterLockedIncrement and InterLockedDecrement
實現數的原子性加減。什麼是原子性的加減呢?
舉個例子:如果一個變量 Long value =0;
首先說一下正常情況下的加減操作:value+=1;
1:系統從Value的空間取出值,並動態生成一個空間來存儲取出來的值;
2:將取出來的值和1作加法,並且將和放回Value的空間覆蓋掉原值。加法結束。
如果此時有兩個Thread ,分別記作threadA,threadB。
1:threadA將Value從存儲空間取出,為0;
2:threadB將Value從存儲空間取出,為0;
3:threadA將取出來的值和1作加法,並且將和放回Value的空間覆蓋掉原值。加法結束,Value=1。
4:threadB將取出來的值和1作加法,並且將和放回Value的空間覆蓋掉原值。加法結束,Value=1。
最後Value =1 ,而正確應該是2;這就是問題的所在,InterLockedIncrement 能夠保證在一個線程訪問變量時其它線程不能訪問。同理InterLockedDecrement。
LONG InterlockedDecrement(
LPLONG lpAddend // variable address
);
屬於互鎖函數,用在同一進程內,需要對共享的一個變量,做減法的時候,
防止其他線程訪問這個變量,是實現線程同步的一種辦法(互鎖函數)
首先要理解多線程同步,共享資源(同時訪問全局變量的問題),否則就難以理解。
result = InterlockedDecrement(&SomeInt)
如果不考慮多線程其實就是 result = SomeInt - 1;
但是考慮到多線程問題就復雜了一些。就是說如果想要得到我預期的結果並不容易。
result = SomeInt - 1;
舉例說:
SomeInt如果==1;
預期的結果result當然==0;
但是,如果SomeInt是一個全程共享的全局變量情況就不一樣了。
C語言的"result = SomeInt - 1;"
在實際的執行過程中,有好幾條指令,在指令執行過程中,其它線程可能改變SomeInt值,使真正的結果與你預期的不一致。
所以InterlockedDecrement(&SomeInt)的執行過程是這樣的
{
__禁止其他線程訪問 (&SomeInt) 這個地址
SomeInt --;
move EAX, someInt; // 設定返回值,C++函數的返回值 都放在EAX中,
__開放其他線程訪問 (&SomeInt) 這個地址
}
但是實際上只需要幾條指令加前綴就可以完成,以上說明是放大的。
你也許會說,這有必要嗎? 一般來說,發生錯誤的概率不大,但是防范總是必要的
如果不考慮多線程
result = InterlockedDecrement(&SomeInt);
就是result = SomeInt - 1;
如果SomeInt==1,result一定==0;
但是,在多線程中如果SomeInt是線程間共享的全局變量,情況就不那麼簡單了。
result = SomeInt - 1;
在CPU中,要執行好幾條指令。在指令中間有可能SomeInt被線程修改。那實際的結果就不是你預期的結果了。
InterlockedDecrement(&SomeInt)
放大的過程,如下:
{
__禁止其他線程訪問 &SomeInt 地址;
SomeInt --;
/////其他線程不會在這裡修改SomeInt值。 !!!!!!
mov EAX, SomeInt; //C++ 函數返回值 總放在EAX中。
__開放其他線程訪問 &SomeInt 地址;
}
實際的CPU執行過程只有幾條加前綴的指令(586指令)
你會說,有必要嗎? 出錯的概率不大,但是錯誤總是需要防范的。當然可以用其他多線程機制實現,但是都沒有這樣簡潔,所以Interlocked...函數有必要提供。