2011-08-03 33 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. 原始值递增并写入,无效之前的原子更新

此外,你需要两个相同的相同的关键部分,因为它无法锁定单独的东西。 :)