棘手的InterlockedDecrement与CriticalSection相关

时间:2011-08-03 17:43:50

标签: c++ winapi thread-safety

有全球long count柜台 线程A

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

线程B

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

在(* 1),我处于一个关键部分。在(* 2),我不是。

没有InterlockedIncrement(),(* 1)安全吗? (它是受保护的关键部分) 我需要InterlockedIncrement()(* 1)吗? 我觉得我可以赞成和反对。

3 个答案:

答案 0 :(得分:5)

你应该使用其中一种,而不是混合它们。

虽然InterlockedDecrement保证是原子的,但operator++不是,但在这种情况下,它可能取决于您的架构。在这种情况下,您实际上并没有实际保护count变量。

鉴于您似乎想要进行简单的inrecrement / decrement操作,我建议您在这种情况下删除关键部分并使用相关的Interlocked*函数。

答案 1 :(得分:4)

两个主题都应使用 <{strong> 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都确保了减量的原子性。它不会阻止任何其他线程对变量的过时副本执行计算,然后将结果写回。

答案 2 :(得分:1)

是的,你这样做。

否则可能是:

  1. 读取值

  2. 该值以原子方式递增

  3. 原始值递增并写入,使先前的原子更新无效

  4. 此外,两者都需要相同的关键部分,因为它无法锁定单独的内容。 :)