问题
I have a very simple watchdog program with 2 threads. One thread is updating a long variable and the other thread reads the variable. and alert if it was more than X seconds from the last update. The problem is that sometimes (happens once a day more or less) the second thread reads a stale value of the variable.
Sometimes it is stale value from 3 seconds ago (i.e. the first thread updated the long variable but after 3 seconds the other thread didn't get the new value)
I am using lock, in order to avoid multi thread caching problem. I also tried Volatile, Interlock, volatileRead etc but nothing helps. The class is initiated via VB 6 program via COM. The program is very simple, so i think that it is a bug in C# (maybe COM related). this is the program:
Can you help please?
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);
}
}
}
回答1:
while (WatchdogActive)
That doesn't work, WatchdogActive isn't declared volatile. In the Release build the variable is very likely to get stored in a CPU register, it never sees the update that some other thread makes to the variable. In other words, the watch dog will still be active, even though you turned it off.
You should use a ManualResetEvent here, its WaitOne(int) method automatically takes care of the Sleep() and gives you a much quicker thread termination as a bonus.
Some strange inconsistencies. You quote a failure at 3 seconds but you only check for >= 5 seconds. The Sleep() is longer than the check, making it possible to miss failures. You seem to like empty catch blocks, always giving great opportunities for code failing to work without any diagnostic. I'm guessing we're not looking at the real code, that makes it difficult to see subtle threading problems. Do work from the assumption that this is not a bug in C#.
回答2:
normally i use lock() to volatile object that is on 'left side' in this case, use
volatile object lastDate = DateTime.Now.ToBinary();
...
lock(lastDate){...}
And why u pass 'long' instead of DateTime?
来源:https://stackoverflow.com/questions/4537447/very-strange-and-severe-multithread-inconsistency-problem-c-sharp