InterlockedExchange在vmware下失败,解决方法?

时间:2012-04-30 11:35:42

标签: c winapi vmware esxi

一种非常简单的方法。 两个线程。

volatile __int32 p=0;

一个线程(A)仅使用

while(1){
    ExecuteAVeryCPUIntesiveThing();
    InterlockedExchange(&p, 0);
}

另一个线程(B)使用

while(1){
    if(0==InterlockedCompareExchange(&p,0,0))
        InterlockedExchange(&p, 1);
}

如果有人试图在压力下的系统下记录它。 (很多内存交换,io,socket,cpu峰值..) 来自A的值不会传播到B。

在A中,p值似乎为0。 但是从B的角度来看,p被困在1。 在我的世界中,当A将值设置为0时,B应该检测并将值设置为0。 而真正的hw就是这样,但在esxi上运行时却没有。

这似乎在真实硬件下和某些虚拟系统下运行良好,但在vmware下则不行。

我做过心灵滑动还是......?

OS guest:win2008服务器

使用Microsoft(R)C / C ++优化编译器版本15.00.30729.01 for x64编译的代码

主持人:esxi 4.1

更新

对评论的回应:是的,它会在0到1之间反弹,   但正如所写的那样,线程B不会反弹,因为从P的角度来看,p的值永远不会发生变化,它会反弹10-20次然后停止。

我想只在非常精确的时刻执行A(ExecuteAVeryCPUIntesiveThing();)中的代码块。

生产代码已满,包含更多线程和事件,互斥锁和锁,但事实仍然是,如果我剥离并仅使用上面的代码,我可以重现它,如果我在客户操作系统上生成大量的cpu,mm,io

1 个答案:

答案 0 :(得分:2)

此代码是等待发生的线程竞赛。您可能是从VMWare获得的,因为您只为虚拟机分配了一个处理器。

缺少的代码是一个互锁,确保线程B 看到 p更改的值。因此,如果线程A获取了cpu核心并且保持运行一段时间并且线程B被阻塞,则等待量程运行,然后线程A可以将p设置为多于0次。线程B将忽略它,因为它永远没有机会将p设置回1。

您需要重新考虑锁定设计。问题不仅限于VMWare,它也可能在普通机器上出错,只是不太可能。它每月出错一次,给予或接受,无法调试。这是一个典型的生产者/消费者场景,你使用线程安全队列来解决这个问题。