我有一个非常简单的监视程序,有2个线程。一个线程正在更新一个长变量,另一个线程正在读取该变量。如果距离上次更新超过X秒,则发出警报。问题是有时(或多或少每天发生一次)第二个线程读取变量的陈旧值。
有时它是3秒前的陈旧值(即第一个线程更新了长变量,但是3秒后其他线程没有获得新值)
我正在使用锁,以避免多线程缓存问题。我也尝试过Volatile,Interlock,volatileRead等,但没有任何帮助。该类通过COM通过VB 6程序启动。该程序非常简单,所以我认为它是C#中的一个错误(可能与COM相关)。这是该计划:
你能帮帮忙吗?
public class WatchDog
{
long lastDate = DateTime.Now.ToBinary();
private object dateLock = new object();
bool WatchdogActive = true;
int WatchdogTimeoutAlert = 5;
int WatchdogCheckInterval = 6000;
private void WatchdogThread()
{
try
{
while (WatchdogActive)
{
lock (dateLock)
{
DateTime lastHB = DateTime.FromBinary(lastDate);
if ((DateTime.Now.Subtract(lastHB).TotalSeconds > WatchdogTimeoutAlert))
{
Console.WriteLine(" last Date is " + lastDate);
}
}
Thread.Sleep(WatchdogCheckInterval);
}
}
catch (Exception Ex)
{
}
}
private void OnHeartbeatArrive(long heartbeatTime)
{
lock (dateLock)
{
lastDate = heartbeatTime;
Console.WriteLine(" Got Heartbeat lastDate " + lastDate);
}
}
}
答案 0 :(得分:3)
while (WatchdogActive)
这不起作用,WatchdogActive未声明 volatile 。在Release版本中,变量很可能存储在CPU寄存器中,它永远不会看到其他线程对变量所做的更新。换句话说,即使您关闭了看门狗,看门狗仍然会处于活动状态。
你应该在这里使用ManualResetEvent,它的WaitOne(int)方法会自动处理Sleep(),并为你提供更快的线程终止作为奖励。
一些奇怪的不一致。您在3秒时引用失败,但只检查> = 5秒。 Sleep()比检查更长,可以错过故障。您似乎喜欢空的catch块,总是为代码在没有任何诊断的情况下无法工作提供了很好的机会。我猜我们没有看到真正的代码,这使得很难看到细微的线程问题。假设这不是C#中的错误。
答案 1 :(得分:0)
通常我会将lock()用于在这种情况下位于“左侧”的volatile对象,使用
volatile object lastDate = DateTime.Now.ToBinary();
...
lock(lastDate){...}
为什么你通过'long'而不是DateTime?