C# Exception

Gast #4024890
Lesenswert?

Bei einer C# Applikation tritt nach einer bestimmten Zeit ein Fehler 
auf. Der Wert ticks ist negative. Warum kann die Variable ticks negativ 
werden? Wahrscheinlich handelt es sich hierbei um einen Überlauf. Wie 
könnte man sowas ändern, damit solch eine Meldung nicht mehr erscheint?
1
Stop = _myQueryPerfCounter.Stop();
2
DateTime datetime = _List[index].StartTime;
3
DiffTime = _myQueryPerfCounter.Duration(_List[index].Start, Stop);
4
long ticks = datetime.Ticks;
5
ticks = ticks + (long)DiffTime;
6
datetime = new DateTime(ticks);
Gast #4025038
Lesenswert?

Hab ausversehen den Screnshot von der Fehlermeldung (Visual Studio) 
gelöscht. Was könnte getan werden, wenn der Fehler nochmals auftreten 
sollte? Mit try und catch fange ich den Fehler ab. Ist das der richtige 
Weg?
Gast #4025044
Lesenswert?

csharpuser schrieb:
> Was könnte getan werden, wenn der Fehler nochmals auftreten
> sollte?

den Fehler beheben, wenn der wert überläuft ist halt die Variabel zu 
klein.

>  Mit try und catch fange ich den Fehler ab. Ist das der richtige
> Weg?
wenn du das Ergebnis nicht brauchst, kann man das schon machen.
Gast #4025276
Lesenswert?

Arc Net schrieb:
> Sven B. schrieb:
>> long ticks = datetime.Ticks << hier ist der Fehler
>>
>> Ticks ist ein QUAD !
>>
>> mach mal
>>
>> int64 ticks = datetime.Ticks
>>
>> siehe MSDN
>
> Genau...
> 
https://msdn.microsoft.com/de-de/library/system.datetime.ticks%28v=vs.110%29.aspx
>
> public long Ticks { get; }
>
> Ansonsten hätte der Compiler einen Fehler geworfen und auf einen
> nötigen, expliziten Cast hingewiesen...

Auf der MS-Seite steht expilzit: Typ: System.Int64
Bin vor kurzen selber über das Problem gestolpert, dass ich Ticks als 
long definiert und unsinnige Ergebnisse erhalten hatte.
Gast #4026219
Lesenswert?

Ich habe nun die Applikation eine ganze Nacht durchlaufen lassen. Visual 
Studio erzeugt wieder die gleiche Meldung: siehe Dateianhang
1
Informationen ueber das Aufrufen von JIT-Debuggen
2
anstelle dieses Dialogfelds finden Sie am Ende dieser Meldung.
3

4
************** Ausnahmetext **************
5
System.ArgumentOutOfRangeException: Ticks muessen sich zwischen DateTime.MinValue.Ticks und DateTime.MaxValue.Ticks befinden.
6
Parametername: ticks
7
   bei System.DateTime..ctor(Int64 ticks)
8
   bei Zeit.Zeitmessung.TimerTick(Object sender, EventArgs e)
Angehängte Dateien:
Gast #4026322
Lesenswert?

csharpuser schrieb:
> Was könnte getan werden, wenn der Fehler nochmals auftreten
> sollte? Mit try und catch fange ich den Fehler ab. Ist das der richtige
> Weg?

Das Problem scheint ja inzwischen behoben zu sein. Generell würde ich 
bei solchen nur gelegentlich auftauchenden Problemen folgendermaßen 
vorgehen:
* try/catch ist schon mal gut, dann muss dein Programm nicht abstürzen.
* Die Exception komplett, mit Stacktrace ausgeben oder besser in ein 
Logfile schreiben.

Wenn dein Programm etwas größer ist würde ich überlegen ein 
Logging-Framework, z.B. Log4net, einzusetzen. Dann kannst du die 
Debug-Ausgaben im Code drinlassen, auch wenn du später weniger oder fast 
gar nichts mehr ausgeben willst.
Gast #4026365
Lesenswert?

csharpuser schrieb:
> Wie schreibe ich einen Stacktrace in eine Textdatei?

Datei öffnen
stracktrace reinschreiben
Datei schließen.


Das hilft dir aber für dein Problem nicht weiter. Du musst dir einfach 
überlegen wie es dazu kommen kann das Ticks einen ungültigen 
Wertebereich annimmt. Dann baust du extra Prüfungen in deinen code ein 
um zu ermitteln wo es zu diesen Problem kommt.
Gast #4026609
Lesenswert?

@csharpuser:
Das Hauptproblem ist, dass Du irgendwelche Codeschnipsel postest, denen 
wesentliche Informationen fehlen: Die Typen der Variable und Felder.

Du schreibst, dass Du eine Exception bekommst, weil ticks negativ ist. 
Das kann nur in der Zeile
1
ticks = ticks + (long)DiffTime;
zum Problem werden. Es würde sich mir die Frage aufdrängen, wieso Ticks 
negativ ist? Möglicherweise weil die Argumente in der Zeile
1
DiffTime = _myQueryPerfCounter.Duration(_List[index].Start, Stop);
vertauscht sind? Das ist aber nur eine Vermutung. Mehr Infos gibt's mit 
Sicherheit in der API-Doku. Dazu müsste man aber vor allem die 
beteiligten Typen kennen. Vielleicht postet Du mal etwas mehr Code...

Grüße
Markus
Gast #4026625
Lesenswert?

Ich habe nun mal die relevanten Codezeilen unten gepostet:

[c]
long    Start;
long    Stop;
double  dDiffTime;
DateTime StartTime;
long     StartCounter;

// OnTimer
private void OnTimer()
{
 ...
 Start = _myQueryPerfCounter.Start();
 StartTime = DateTime.Now;
 StartCounter = Start;
 Start = 0;
 Stop = 0;
 ...
}

private void Callback(...)
{
 ...
 Stop = _myQueryPerfCounter.Stop();
 DateTime datetime = StartTime;
 dDiffTime = _myQueryPerfCounter.Duration(StartCounter, Stop);
 Int64 ticks = datetime.Ticks;
 ticks = ticks + (Int64)dDiffTime;
 datetime = new DateTime(ticks);
 ...
}
Gast #4026699
Lesenswert?

1
long    Start;
2
long    Stop;
3
double  dDiffTime;
4
DateTime StartTime;
5
long     StartCounter;
6

7
// OnTimer
8
private void OnTimer()
9
{
10
 ...
11
 Start = _myQueryPerfCounter.Start();
12
 StartTime = DateTime.Now;
13
 StartCounter = Start;
14
 Start = 0;
15
 Stop = 0;
16
 ...
17
}
18

19
private void Callback(...)
20
{
21
 ...
22
 Stop = _myQueryPerfCounter.Stop();
23
 DateTime datetime = StartTime;
24
 dDiffTime = _myQueryPerfCounter.Duration(StartCounter, Stop);
25
 Int64 ticks = datetime.Ticks;
26
 ticks = ticks + (Int64)dDiffTime;
27
 datetime = new DateTime(ticks);
28
 ...
29
}
Gast #4026715
Lesenswert?

Sorry hab ich vergessen.
1
class MyQueryPerfCounter
2
{
3
    [DllImport("KERNEL32")]
4
    private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
5

6
    [DllImport("Kernel32.dll")]
7
    private static extern bool QueryPerformanceFrequency(out long lpFrequency);
8

9
    private long frequency;
10
    Decimal multiplier = new Decimal(1.0e9);
11

12
    public MyQueryPerfCounter()
13
    {
14
        if (QueryPerformanceFrequency(out frequency) == false)
15
        {
16
            // Frequency not supported
17
            throw new Win32Exception();
18
        }
19
    }
20

21
    public long Start()
22
    {
23
        long start;
24
        QueryPerformanceCounter(out start);
25
        return start;
26
    }
27

28
    public long Stop()
29
    {
30
        long stop;
31
        QueryPerformanceCounter(out stop);
32
        return stop;
33
    }
34

35
    public double Duration(long start, long stop)
36
    {
37
        return ((((double)(stop - start) * (double)multiplier) / (double)frequency) / 1000000);
38
    }
39

40
}
41

42
MyQueryPerfCounter _myQueryPerfCounter = new MyQueryPerfCounter();
Gast #4026752
Lesenswert?

was hast du für eine CPU?

Es gibt bei AMD das Problem das jeder Kern seine eigenen Counter hat. 
Das kann dazu führen das nach einen Taskwechsel das Ende vor den Start 
ist. Dafür gibt es von ADM ein tool was das verhindert.

Oder du musst dafür sorgen, das du nur auf einen Kern läufst.
Gast #4026757
Lesenswert?

So auf den ersten Blick sieht das zwar etwas wirr, aber soweit ok aus. 
Bist Du sicher, dass die Handler OnTimer und Callback in der richtigen 
Reihenfolge aufgerufen werden? Das ist, so wie ich es sehe, die einzige 
Möglichkeit, dass die Tick-Differenz negativ wird.

Grüße
Markus
Gast #4026761
Lesenswert?

Was vielleicht helfen würde: Speichere Start und Stop als Felder der 
Klasse MyQueryPerfcounter zu speichern und dann beim Aufruf von Duration 
diese zu verwenden. Das wäre ein wesentlich besseres Design.

Grüße
Markus
Gast #4026948
Lesenswert?

Bei welcher Gelegenheit wird eigentlich die Methode Callback aufgerufen? 
Mit welchen Parametern? Wo wird die Callback-Methode als Event-Handler 
registriert?

Ich bin der festen Überzeugung, dass Du ein Nebenläufigkeitsproblem 
hast. Soll heißen, der Callback-Handler wird in einem anderen Thread als 
OnTimer aufgerufen. Dabei kann es dann dazu kommen, dass das nächste 
OnTimer vor dem letzten Callback-Aufruf kommt. Deshalb musst Du 
geeignete Maßnahmen ergreifen, damit die Zeitmessung (?) mit den 
richtigen Werten arbeitet.

Grüße
Markus
Gast #4027873
Lesenswert?

Guten Morgen,

ich vermute auch, dass ich eventuell ein Nebenläufigkeitsproblem habe.
In der OnTimer Funktion wird jede Sekunde ein Ping gesendet mit der 
Methode SendAsync. In der Callback Methode PingCompletedCallback werden 
die Antworten empfangen bzw. wird ausgeführt wenn ein Timeout 
aufschlägt.
Die OnTimer Methode wird mit, sie unten, angelegt bzw. erzeugt.
1
this.Invoke(new InvokeProc(OnTimer));
Gast #4027886
Lesenswert?

Hab ich bereits in der Duration Methode gemacht. Allerdings muss die 
Prüfung start > stop sein.

[c]
if (start > stop)
{
 Console.WriteLine("Timestamp: " + DateTime.Now.ToString() + " start: " 
+  start.ToString() + " stop: " + stop.ToString());
}

Das Programm lief nun ca. 15 Stunden ohne Probleme durch. Visual Studio 
erzeugte keine Fehlermeldung.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren