一种非常简单的方法。 两个线程。
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
答案 0 :(得分:2)
此代码是等待发生的线程竞赛。您可能是从VMWare获得的,因为您只为虚拟机分配了一个处理器。
缺少的代码是一个互锁,确保线程B 看到 p
更改的值。因此,如果线程A获取了cpu核心并且保持运行一段时间并且线程B被阻塞,则等待量程运行,然后线程A可以将p
设置为多于0次。线程B将忽略它,因为它永远没有机会将p
设置回1。
您需要重新考虑锁定设计。问题不仅限于VMWare,它也可能在普通机器上出错,只是不太可能。它每月出错一次,给予或接受,无法调试。这是一个典型的生产者/消费者场景,你使用线程安全队列来解决这个问题。