Forum: PC-Programmierung C# Exception


von csharpuser (Gast)


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);

von Peter II (Gast)


Lesenswert?

csharpuser schrieb:
> Warum kann die Variable ticks negativ
> werden?

keine Ahnung, gibt doch mal die werte aus.

ticks = ticks + (long)DiffTime;

auch bei einen Long ist irgendwann mal schluss.

und was sagt denn die exception aus

von csharpuser (Gast)


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?

von Peter II (Gast)


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.

von Sven B. (svb)


Lesenswert?

long ticks = datetime.Ticks << hier ist der Fehler

Ticks ist ein QUAD !

mach mal

int64 ticks = datetime.Ticks

siehe MSDN

von bluppdidupp (Gast)


Lesenswert?

Statt "_myQueryPerfCounter" könnte auch direkt die StopWatch-Klasse 
benutzt werden: 
https://msdn.microsoft.com/de-de/library/system.diagnostics.stopwatch%28v=vs.110%29.aspx
(verwendet intern Performance Counter)

von Arc N. (arc)


Lesenswert?

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...

von Muc (Gast)


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.

von Peter II (Gast)


Lesenswert?

Muc schrieb:
> 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.

https://msdn.microsoft.com/de-de/library/ctetwysk.aspx

von Muc (Gast)


Lesenswert?

Peter II schrieb:
> Muc schrieb:
>> 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.
>
> https://msdn.microsoft.com/de-de/library/ctetwysk.aspx
Stimmt auch wieder ...

von csharpuser (Gast)


Angehängte Dateien:

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)

von Kaspar Hauser (Gast)


Lesenswert?

Was gibt _myQueryPerfCounter.Duration eigentlich zurück (Typ und 
Einheit)? Hast du diesen Wert und ticks im Fehlerfall geloggt oder dir 
zumindest mal im Debugger angeschaut?

von csharpuser (Gast)


Lesenswert?

Habe ich nicht. Wusste nicht wie das mit dem Debugger funktioniert.

von Anonymous Coder (Gast)


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.

von csharpuser (Gast)


Lesenswert?

Das Problem ist doch nicht behoben. Die Meldung erscheint trotz 
Änderung.

von csharpuser (Gast)


Lesenswert?

>>* Die Exception komplett, mit Stacktrace ausgeben oder besser in ein
Logfile schreiben.

Wie schreibe ich einen Stacktrace in eine Textdatei?

von Peter II (Gast)


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.

von Markus (Gast)


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

von csharpuser (Gast)


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);
 ...
}

von csharpuser (Gast)


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
}

von Markus (Gast)


Lesenswert?

Und der Typ von _myQueryPerfCounter?

von csharpuser (Gast)


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();

von Peter II (Gast)


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.

von Markus (Gast)


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

von Markus (Gast)


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

von csharpuser (Gast)


Lesenswert?

Ich verwende einen Laptop mit folgender CPU:

Intel Core i/ CPU (Windows7 64Bit)

von csharpuser (Gast)


Lesenswert?

Korrektur: Intel Core i7 CPU (Windows7 64Bit)

von csharpuser (Gast)


Lesenswert?

Was könnte man tun, damit wenn die Callback Methode vor der OnTimer 
ausgeführt wird?

In der OnTimer wird zyklisch eine Methode gestartet. In der Callback 
Methode wird dann reingesprungen.

von Peter II (Gast)


Lesenswert?

csharpuser schrieb:
> Korrektur: Intel Core i7 CPU (Windows7 64Bit)

ok, das sollte das Problem nicht auftreten.

Bau mal in der funktion Duration eine Prüfung ein, die eine exception 
wirft, wenn start > stop ist.

von csharpuser (Gast)


Lesenswert?

Was müsste ich genau tun, damit die GUI Applikation nur mit einem Core 
läuft?

von Peter II (Gast)


Lesenswert?

csharpuser schrieb:
> Was müsste ich genau tun, damit die GUI Applikation nur mit einem Core
> läuft?

https://msdn.microsoft.com/en-us/library/windows/desktop/ms686223(v=vs.85).aspx

aber wie gesagt, das sollte nur bei älteren AMDs zu einen Problem 
führen. Viel wahrscheinlicher ist, das bei dir die Reihenfolge der 
Funktion nicht immer stimmt.

von Markus (Gast)


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

von csharpuser (Gast)


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));

von Peter II (Gast)


Lesenswert?

bau doch erst mal die Prüfung an, ob start < stop ist, wenn das nicht 
der Fall ist wirf eine exeception.

von csharpuser (Gast)


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.

von csharpuser (Gast)


Lesenswert?

1
if (start > stop)
2
{
3
 Console.WriteLine("Timestamp: " + DateTime.Now.ToString() + " start: " 
4
+  start.ToString() + " stop: " + stop.ToString());
5
}

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.