2

2 つのスレッドを持つ非常に単純なウォッチドッグ プログラムがあります。1 つのスレッドが long 変数を更新し、もう 1 つのスレッドがその変数を読み取ります。最後の更新から X 秒以上経過した場合は警告します。問題は、2 番目のスレッドが変数の古い値を読み取ることがある (ほぼ 1 日に 1 回発生する) ことです。

3 秒前の古い値である場合があります (つまり、最初のスレッドが long 変数を更新しましたが、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);
        }
    }
}
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){...}

また、DateTime の代わりに「long」を渡すのはなぜですか?

于 2010-12-27T09:43:48.933 に答える