2010-12-27 11 views
2

Ich habe ein sehr einfaches Watchdog-Programm mit 2 Threads. Ein Thread aktualisiert eine lange Variable und der andere Thread liest die Variable. und warnt, wenn es länger als X Sekunden nach dem letzten Update war. Das Problem ist, dass der zweite Thread manchmal (mehr oder weniger einmal am Tag) einen veralteten Wert der Variablen liest.sehr seltsame und schwere Multithread Inkonsistenz Problem C#

Manchmal ist es abgestanden Wert von 3 Sekunden (dh des ersten Thread der lange Variable aktualisiert, aber nach 3 Sekunden des andere Thread nicht den neuen Wert bekommen)

I Sperre verwenden, um zu vermeiden, Multi-Thread-Cache-Problem. Ich habe auch Volatile, Interlock, volatileRead usw. versucht, aber nichts hilft. Die Klasse wird über das Programm VB 6 über COM initiiert. Das Programm ist sehr einfach, also denke ich, dass es ein Fehler in C# ist (vielleicht COM bezogen). Dies ist das Programm:

Können Sie bitte helfen?

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

Möglicherweise müssen Sie einige Informationen darüber geben, wie 'OnHeartbeatArrive()' aufgerufen wird und insbesondere, wie die übergebene 'heartbeatTime' bestimmt wird. –

+0

Um klarzustellen, demonstriert der veröffentlichte Code mit den WriteLine() - Anweisungen das Problem? –

+0

@michael Wenn ich eine Nachricht vom Server über TCP erhalte, rufe ich OnHeartbeatArrive mit DateTime.Now.ToBinary() auf. Beachten Sie, dass ich dieselbe Variable drucke. Ich sehe, dass es seinen Wert aus dem Update-Thread geändert hat, aber ich sehe einen alten Wert im Lese-Thread. –

Antwort

3
 while (WatchdogActive) 

, die nicht funktioniert, ist WatchdogActive nicht flüchtigen erklärt. Im Release-Build ist es sehr wahrscheinlich, dass die Variable in einem CPU-Register gespeichert wird, sie sieht niemals die Aktualisierung, die ein anderer Thread für die Variable vornimmt. Mit anderen Worten, der Wachhund ist immer noch aktiv, obwohl Sie ihn ausgeschaltet haben.

Sie sollten hier ein ManualResetEvent verwenden, seine WaitOne (int) -Methode kümmert sich automatisch um den Sleep() und gibt Ihnen eine viel schnellere Thread-Terminierung als Bonus.

Einige seltsame Inkonsistenzen. Sie geben einen Fehler nach 3 Sekunden an, aber Sie prüfen nur nach> = 5 Sekunden. Der Sleep() ist länger als der Check, so dass Fehler übersehen werden können. Sie scheinen leere Catch-Blöcke zu mögen, die immer große Möglichkeiten bieten, dass Code ohne Diagnose nicht funktioniert. Ich schätze, dass wir uns nicht den echten Code anschauen, der es schwierig macht, subtile Threading-Probleme zu sehen. Gehen Sie von der Annahme aus, dass dies kein Fehler in C# ist.

+0

natürlich ist es möglich. Der Leser-Thread überprüft tatsächlich alle 5 Sekunden. Aber der Ablauf ist wie folgt: Der Aktualisierungs-Thread aktualisiert den Wert zur Zeit X-2 und X. Der Reader-Thread weckt bei X + 3, aber erhält nicht den am meisten aktualisierten Wert. Es erhält den Wert von X - 2. –

+0

natürlich ist es möglich. Der Leser-Thread überprüft tatsächlich alle 5 Sekunden. Aber der Ablauf ist wie folgt: Der Aktualisierungs-Thread aktualisiert den Wert zur Zeit X-2 und X. Der Reader-Thread weckt bei X + 3, aber erhält nicht den am meisten aktualisierten Wert. Es erhält den Wert von X - 2. Der Code ist fast identisch mit dem echten Code, wie ich sagte, es ist sehr einfach.Nicht sicher, was du meintest, dass der WatchdogActive nicht flüchtig ist. In den meisten Fällen funktioniert es gut, aber es passiert einmal am Tag. Ich werde glücklich sein zu wissen, dass es nicht C# com Bug ist, aber ich habe keine Ideen mehr. –

+0

Woher weißt du das? Stehst du den ganzen Tag auf das Konsolenfenster, um X zu sehen? Oder wird das tatsächlich protokolliert? Logger haben ihre eigene Verriegelung. Machen Sie das Code-Snippet zu einer * exakten * Kopie des echten Codes. –

0

normalerweise verwende ich lock(), um flüchtiges Objekt, das auf ‚links‘ ist in diesem Fall verwende

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

Und warum u ‚long‘ statt Datetime übergeben?

+0

Probieren Sie es aus: "volatile nicht gültig für Typ lang ..." –

+0

Ich habe alle Optionen ausprobiert. Ich habe versucht mit volatile + lock zu arbeiten, ich habe versucht mit DateTime zu arbeiten, ich habe versucht, mit VolatileRead zu lesen und zu schreiben, ich habe versucht, mit Interlock zu lesen und zu schreiben. Nichts hat geklappt. Eigentlich habe ich mit DateTime begonnen, ich habe es zu lang geändert, nur um zu überprüfen, dass es kein DateTime-Problem ist –

+0

y es funktioniert nicht? Was ist die Ausnahme? Wie ist es gescheitert? – Bonshington