非常奇怪和严重的多线程不一致问题c#

时间:2010-12-27 08:24:14

标签: c# .net multithreading volatile interlocked

我有一个非常简单的监视程序,有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);
        }
    }
}

2 个答案:

答案 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?