2011-08-03 34 views
1

還有全球long count計數器。
線程A確實棘手聯鎖減值與臨界區

EnterCriticalSection(&crit); 
// .... do something 
count++;      // (*1) 
// .. do something else 
LeaveCriticalSection(&crit); 

線程B確實

InterlockedDecrement(&count); // (*2) not under critical secion. 

在(* 1),I是下一個關鍵部分。在(* 2),我不是。

是否(* 1)安全無InterlockedIncrement()? (它是受保護的關鍵部分)。
我需要InterlockedIncrement()(* 1)嗎?
我覺得我可以爭論和反對。

+0

我認爲那裏的鎖是因爲// //做些什麼代碼? –

回答

4

你應該使用其中一個,而不是混合它們。

儘管InterlockedDecrement保證是原子的,但operator++不是,儘管在這種情況下它可能取決於您的體系結構。在這種情況下,你實際上並沒有保護count變量。

鑑於您似乎想要做簡單的增加/減少操作,我建議您只需在這種情況下刪除關鍵部分並使用關聯的Interlocked*函數。

3

兩個線程應該使用要麼InterlockedDecrement/InterlockedIncrement相同的關鍵部分。沒有理由混合和匹配才能正常工作。

考慮事件的順序如下:

Thread A: enter the critical section 
Thread A: read count into a register 
Thread A: increment the value in the register 
Thread B: InterlockedDecrement(&count) <<< There's nothing to stop this from happening! 
Thread A: write the new count 
Thread A: leave the critical section 

最終結果是:你已經失去了一個遞減!

一個有用的(如果故意簡化的)關鍵部分的心理模型是這樣的:所有進入關鍵部分的做法是防止其他線程進入相同的關鍵部分。它不會自動阻止其他線程執行可能需要同步的其他事情。

並且所有InterlockedDecrement都確保了遞減的原子性。它不會阻止任何其他線程在變量的過期副本上執行計算,然後將結果寫回。

1

是的,你這樣做。

否則,它可能是:

  1. 值讀取

  2. 值原子遞增

  3. 原始值遞增並寫入,無效之前的原子更新

此外,你需要兩個相同的相同的關鍵部分,因爲它無法鎖定單獨的東西。 :)