2

我有一个非常简单的看门狗程序,有 2 个线程。一个线程正在更新一个长变量,另一个线程读取该变量。并在距离上次更新超过 X 秒时发出警报。问题是有时(每天或多或少发生一次)第二个线程读取变量的陈旧值。

有时它是 3 秒前的旧值(即第一个线程更新了 long 变量,但 3 秒后另一个线程没有得到新值)

我正在使用锁,以避免多线程缓存问题。我还尝试了 Volatile、Interlock、volatileRead 等,但没有任何帮助。该课程通过 VB 6 程序通过 COM 启动。该程序非常简单,所以我认为这是 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);
        }
    }
}
4

2 回答 2

3
        while (WatchdogActive)

这不起作用, WatchdogActive 没有被声明为volatile。在发布版本中,变量很可能存储在 CPU 寄存器中,它永远不会看到其他线程对变量进行的更新。换句话说,即使您将其关闭,看门狗仍将处于活动状态。

您应该在这里使用 ManualResetEvent,它的 WaitOne(int) 方法会自动处理 Sleep() 并为您提供更快的线程终止作为奖励。

一些奇怪的不一致。您在 3 秒时引用失败,但您只检查 >= 5 秒。Sleep() 比检查长,因此有可能错过失败。你似乎喜欢空的 catch 块,总是为代码在没有任何诊断的情况下无法工作提供很好的机会。我猜我们不是在看真正的代码,这使得很难看到微妙的线程问题。请假设这不是 C# 中的错误。

于 2010-12-27T09:30:05.063 回答
0

通常我在这种情况下对“左侧”的易失性对象使用 lock(),使用

volatile object lastDate = DateTime.Now.ToBinary();
...
lock(lastDate){...}

为什么你通过'long'而不是DateTime?

于 2010-12-27T09:43:48.933 回答