Hallo,
ich benötige für eine Win32-Konsolenanwendung(Visual C++ 2008 Express)
eine bestimmte Anzahl von Zeitstempeln pro Sekunde. Die Abstände der
Zeitstempel sollen durch die Angabe von Millisekunden festgelegt werden.
Meine Versuche, dieses Ziel mit einfachen Timern zu lösen, waren bislang
erfolglos. Sowohl SetTimer als auch WaitableTimer haben offenbar eine
gewisse Drift, die über kurz oder lang dazu führt, dass immer wieder mal
ein Zeitstempel zu wenig erzeugt wird.
Ein Beispiel: Ich stelle das Intervall auf 100ms und sollte daher 10
Zeitstempel pro Sekunde erhalten. Alle paar Sekunden erhalte ich jedoch
nur 9 Zeitstempel pro Sekunde, da die Drift dazu führt, dass die
einzelnen Zeitstempel immer wieder mal um ca. 15ms verzögert erscheinen
und sich dies auch auf die nachfolgenden Zeitstempel auswirkt, so dass
der 10. Wert dann irgendwann durch den Überlauf bei 999ms zur
nachfolgenden Sekunde gehört. Stelle ich das Intervall auf 20ms, erhalte
ich immerhin noch 49 Messungen pro Sekunde. An mangelnder
Geschwindigkeit meines Systems bzw. dem Code im Timeraufruf kann es
somit nicht auscchließlich liegen. Bei z.B. 250ms funktioniert das ganze
wunderbar 4 mal pro Sekunde exakt ohne Drift, obwohl statistisch doch
auch da irgendwann eine Verzögerung zum Tragen kommen müsste?!?
Mir ist klar, dass Windows kein Echtzeit-Betriebssystem ist und es geht
mir auch nicht um auf eine Millisekunde genaue Zeitstempel. Ich suche
vielmehr nach einer einfachen Lösung, um eine Funktion möglichst
periodisch aufzurufen. Wenn die Millisekunden der einzelnen Zeitstempel
dann im niedrigen zweistelligen Bereich schwanken, würde mich das nicht
stören, so lange in jedem von mir festgelegten Millisekunden-Intervall
genau ein Funktionsaufruf erfolgt.
Wirken sich Verzögerungen bei einem Timeraufruf immer auch auf die
nachfolgenden Timeraufrufe aus? Oder ist das Programm fehlerhaft?
Ich könnte jetzt natürlich einen Timer mit möglichst kurzer
Periodendauer programmieren, der dann unter Berücksichtigung der
eigentlich gewünschten Periodendauer ständig prüft, ob er in der
jeweiligen Periode bereits einen Zeitstempel ausgegeben hat - aber ist
das wirklich notwendig bzw. kann mir ein Timer nicht genau diese Arbeit
abnehmen?
Gruß,
Albert
Hi,
ich Frage mich ob dein Timer driftet oder ob gelegentlich ein Event
"verschluckt" wird. Wirf mal einen genauen Blick auf die Zeiten die dir
dein Programm auswirft. Für einen simplen Test würde ich einfach
GetTickCount() anstatt GetSystemTime() verwenden und immer die Differenz
zum vorherigen Schleifendurchlauf ausgeben.
Interessant wird es dann zu sehen, ob die Werte immer >=100ms sind, oder
ob sie im Zeitmittel bei 100ms mit gelegentlichen Ausreißern von n*100ms
sind. In einem Histogramm sollte man das relativ gut sehen können, so
lange der Jitter im Vergleich zur Periodendauer nicht zu groß wird.
Das erste Szenario (immer >= 100ms) würde darauf hindeuten dass der
Timer zwar 100ms läuft, aber dazu noch diverser Overhead kommt den das
Betriebssystem nicht berücksichtigt. Das wäre aber imho ein
Armutszeugnis für einen Timer den man periodisch starten kann.
Ich vermute mal dass du unter Windows schon relativ große Chancen hast
dass gelegentlich der Prozess nicht zuverlässig alle 100ms zum Zug
kommt. Du kannst auch versuchen die Priorität deines Prozesses im
Taskmanager zu erhöhen und möglichst alle ungenützten Programme zu
beenden.
Gruß,
Reinhard
Der Timer tut eigentlich dass was er soll. Er driftet nicht davon - bei
1000 Werten war der Mittelwert +/- 10µs vom Sollwert entfernt. Die
Standardabweichung bewegte sich in der Größenordnung 7ms. Was ich dabei
interessant fand, war dass es immer nur eine handvoll diskrete Werte gab
die immer wieder auftauchten, siehe das angehängte Pseudohistogramm
(x-Achse nicht skaliert!).
Wenn der Timer mal nicht rechtzeitig zum Zug kommt, was bei mir so ab
25ms der Fall war, läuft er gleich danach noch einmal durch. Im
Extremfall, mit eingestellten 5ms, sieht die Ausgabe dann in etwa so
aus:
0
0
16
0
0
15
0
Um auf deine Situation zurückzukommen: Wenn du in einer Sekunde mal nur
9, statt 10 Zeitstempeln bekommst bedeutet das, dass du in einer anderen
dafür 11 bekommst. Wenn du Pech hast, bekommst du eine Weile lang gar
nichts, aber dann dafür eine Menge identischer Zeitstempel.
Wirf mal einen Blick auf die Multimedia Timer von Windows, vielleicht
helfen die dir ja weiter:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd743609.aspx
Gruß,
Reinhard
Die von Reinhard vorgeschlagenen Multimediatimer sollten weiterhelfen.
Einerseits lässt sich mit denen die Timergranularität des Schedulers von
den üblichen 10 msec auf eine msec verringern (mit timeBeginPeriod),
andererseits bieten die auch Funktionen an, in einem definierten Takt
eine Rückruffunktion aufzurufen (mit timeSetEvent) - und das
funktioniert erheblich stabiler und zuverlässiger als das, was der
Threadstarter da schildert.
Auch wenn die Dokumentation timeSetEvent als obsolete bezeichnet, man
kann sie verwenden.
Worauf Du allerdings achten solltest, ist, daß die aufgerufene
Rückruffunktion nicht allzuviel Rechenzeit verbraucht. Bedenke auch, daß
sie in einem anderen Threadkontext läuft als Dein Hauptprogramm.
Hallo,
vielen Dank für eure Hilfe erstmal. Von Reinhard inspiriert habe ich
noch ein paar Tests gemacht. Neben dem Zeitstempel gebe ich noch die
aktuelle Timer-Runde sowie die zeitliche Differenz zwischen zwei
Timer-Aufrufen aus:
Die folgenden Werte habe ich dann als Ergebnis erhalten:
1
11.38.42.796 - 001 - 0
2
11.38.42.890 - 002 - 94
3
11.38.43.000 - 003 - 109
4
11.38.43.093 - 004 - 94
5
11.38.43.203 - 005 - 109
6
11.38.43.296 - 006 - 94
7
11.38.43.390 - 007 - 94
8
11.38.43.500 - 008 - 109
9
11.38.43.593 - 009 - 94
10
11.38.43.703 - 010 - 109
11
11.38.43.796 - 011 - 94
12
11.38.43.906 - 012 - 109
13
11.38.44.000 - 013 - 94
14
11.38.44.093 - 014 - 94
15
11.38.44.203 - 015 - 109
16
11.38.44.296 - 016 - 94
17
11.38.44.406 - 017 - 109
18
11.38.44.500 - 018 - 94
19
11.38.44.609 - 019 - 109
20
11.38.44.703 - 020 - 94
21
11.38.44.812 - 021 - 110
22
11.38.44.906 - 022 - 93
23
11.38.45.000 - 023 - 94
24
11.38.45.109 - 024 - 109
25
11.38.45.203 - 025 - 94
26
11.38.45.312 - 026 - 110
27
11.38.45.406 - 027 - 93
28
11.38.45.515 - 028 - 110
29
11.38.45.609 - 029 - 93
30
11.38.45.703 - 030 - 94
31
11.38.45.812 - 031 - 110
32
11.38.45.906 - 032 - 93
33
11.38.46.015 - 033 - 110
34
11.38.46.109 - 034 - 93
35
11.38.46.218 - 035 - 110
36
11.38.46.312 - 036 - 94
37
11.38.46.421 - 037 - 109
38
11.38.46.515 - 038 - 94
39
11.38.46.609 - 039 - 93
40
11.38.46.718 - 040 - 110
41
11.38.46.812 - 041 - 94
42
11.38.46.921 - 042 - 109
43
11.38.47.015 - 043 - 94
44
11.38.47.125 - 044 - 109
45
11.38.47.218 - 045 - 94
46
11.38.47.312 - 046 - 94
47
11.38.47.421 - 047 - 109
48
11.38.47.515 - 048 - 94
49
11.38.47.625 - 049 - 109
50
11.38.47.718 - 050 - 94
51
11.38.47.828 - 051 - 109
52
11.38.47.921 - 052 - 94
53
11.38.48.031 - 053 - 109
54
11.38.48.125 - 054 - 94
55
11.38.48.218 - 055 - 94
56
11.38.48.328 - 056 - 109
57
11.38.48.421 - 057 - 94
58
11.38.48.531 - 058 - 109
59
11.38.48.625 - 059 - 94
60
11.38.48.734 - 060 - 109
61
11.38.48.828 - 061 - 94
62
11.38.48.921 - 062 - 94
63
11.38.49.031 - 063 - 109
64
11.38.49.125 - 064 - 94
65
11.38.49.234 - 065 - 109
66
11.38.49.328 - 066 - 94
67
11.38.49.437 - 067 - 110
68
11.38.49.531 - 068 - 93
69
11.38.49.640 - 069 - 110
70
11.38.49.734 - 070 - 93
71
11.38.49.828 - 071 - 94
72
11.38.49.937 - 072 - 110
73
11.38.50.031 - 073 - 93
74
11.38.50.140 - 074 - 110
75
11.38.50.234 - 075 - 93
76
11.38.50.343 - 076 - 110
77
11.38.50.437 - 077 - 94
78
11.38.50.531 - 078 - 93
79
11.38.50.640 - 079 - 110
80
11.38.50.734 - 080 - 93
81
11.38.50.843 - 081 - 110
82
11.38.50.937 - 082 - 94
83
11.38.51.046 - 083 - 109
84
11.38.51.140 - 084 - 94
85
11.38.51.250 - 085 - 109
86
11.38.51.343 - 086 - 94
87
11.38.51.437 - 087 - 94
88
11.38.51.546 - 088 - 109
89
11.38.51.640 - 089 - 94
90
11.38.51.750 - 090 - 109
91
11.38.51.843 - 091 - 94
92
11.38.51.953 - 092 - 109
93
11.38.52.046 - 093 - 94
94
11.38.52.140 - 094 - 94
95
11.38.52.250 - 095 - 109
96
11.38.52.343 - 096 - 94
97
11.38.52.453 - 097 - 109
98
11.38.52.546 - 098 - 94
99
11.38.52.656 - 099 - 109
100
11.38.52.750 - 100 - 94
101
11.38.52.859 - 101 - 109
102
11.38.52.953 - 102 - 94
103
11.38.53.046 - 103 - 94
104
11.38.53.156 - 104 - 109
105
11.38.53.250 - 105 - 94
106
11.38.53.359 - 106 - 109
107
11.38.53.453 - 107 - 94
108
11.38.53.562 - 108 - 110
109
11.38.53.656 - 109 - 93
110
11.38.53.750 - 110 - 94
111
11.38.53.859 - 111 - 109
112
11.38.53.953 - 112 - 94
113
11.38.54.062 - 113 - 110
114
11.38.54.156 - 114 - 93
115
11.38.54.265 - 115 - 110
116
11.38.54.359 - 116 - 93
117
11.38.54.468 - 117 - 110
118
11.38.54.562 - 118 - 94
119
11.38.54.656 - 119 - 93
120
11.38.54.765 - 120 - 110
121
11.38.54.859 - 121 - 93
122
11.38.54.968 - 122 - 110
123
11.38.55.062 - 123 - 94
124
11.38.55.171 - 124 - 109
125
11.38.55.265 - 125 - 94
126
11.38.55.359 - 126 - 93
127
11.38.55.468 - 127 - 110
128
11.38.55.562 - 128 - 94
129
11.38.55.671 - 129 - 109
130
11.38.55.765 - 130 - 94
131
11.38.55.875 - 131 - 109
132
11.38.55.968 - 132 - 94
133
11.38.56.078 - 133 - 109
134
11.38.56.171 - 134 - 94
135
11.38.56.265 - 135 - 94
136
11.38.56.375 - 136 - 109
137
11.38.56.468 - 137 - 94
138
11.38.56.578 - 138 - 109
139
11.38.56.671 - 139 - 94
140
11.38.56.781 - 140 - 109
141
11.38.56.875 - 141 - 94
142
11.38.56.968 - 142 - 94
143
11.38.57.078 - 143 - 109
144
11.38.57.171 - 144 - 94
145
11.38.57.281 - 145 - 109
146
11.38.57.375 - 146 - 94
147
11.38.57.484 - 147 - 109
148
11.38.57.578 - 148 - 94
149
11.38.57.687 - 149 - 110
150
11.38.57.781 - 150 - 93
151
11.38.57.875 - 151 - 94
152
11.38.57.984 - 152 - 109
153
11.38.58.078 - 153 - 94
154
11.38.58.187 - 154 - 110
155
11.38.58.281 - 155 - 93
156
11.38.58.390 - 156 - 110
157
11.38.58.484 - 157 - 93
158
11.38.58.578 - 158 - 94
159
11.38.58.687 - 159 - 110
160
11.38.58.781 - 160 - 93
161
11.38.58.890 - 161 - 110
162
11.38.58.984 - 162 - 93
163
11.38.59.093 - 163 - 110
164
11.38.59.187 - 164 - 94
165
11.38.59.296 - 165 - 109
166
11.38.59.390 - 166 - 94
167
11.38.59.484 - 167 - 93
168
11.38.59.593 - 168 - 110
169
11.38.59.687 - 169 - 94
170
11.38.59.796 - 170 - 109
171
11.38.59.890 - 171 - 94
172
11.39.00.000 - 172 - 109
173
11.39.00.093 - 173 - 94
174
11.39.00.187 - 174 - 94
175
11.39.00.296 - 175 - 109
176
11.39.00.390 - 176 - 94
177
11.39.00.500 - 177 - 109
178
11.39.00.593 - 178 - 94
179
11.39.00.703 - 179 - 109
180
11.39.00.796 - 180 - 94
181
11.39.00.906 - 181 - 109
182
11.39.01.000 - 182 - 94
183
11.39.01.093 - 183 - 94
184
11.39.01.203 - 184 - 109
185
11.39.01.296 - 185 - 94
186
11.39.01.406 - 186 - 109
187
11.39.01.500 - 187 - 94
188
11.39.01.609 - 188 - 109
189
11.39.01.703 - 189 - 94
190
11.39.01.796 - 190 - 94
191
11.39.01.906 - 191 - 109
192
11.39.02.000 - 192 - 94
193
11.39.02.109 - 193 - 109
194
11.39.02.203 - 194 - 94
195
11.39.02.312 - 195 - 110
196
11.39.02.406 - 196 - 93
197
11.39.02.515 - 197 - 110
198
11.39.02.609 - 198 - 93
199
11.39.02.703 - 199 - 94
200
11.39.02.812 - 200 - 110
Wenn ich das richtig sehe, driftet mein Timer definitiv: immer wieder
mal ungefähr +15ms(z.B. in Sekunde 43 und dann wieder in Sekunde 46,
usw.). In Sekunde 59 führt diese Drift dann zu einem Überlauf bzw. dazu,
dass nur 9 Zeitstempel angezeigt werden. Was mich jetzt wundert ist,
dass es bei Dir, Reinhard, anscheinend zu keiner Timer-Drift kommt.
Könntest Du vielleicht den von mir verwendeten Code auf Deinem Rechner
testen?
Ich werde mir heute aber auch mal die von euch vorgeschlagenen
Multimediatimer ansehen.
Gruß,
Albert
@ Albert
hast du eventuell ein AMD DualCore system? Dann die Athlons haben ohne
das Passen AMD-Tool ein Problem mit dem Timer. Jeder Core hat seinen
eignen Timer und sie laufen nicht Synchron. Wenn jetzt Windows deinen
Thread zwischen den Cores verteilt dann kann das durchaus zu diesen
Problemen kommen. Als abhilfe gibt es von amd den Dualcore optimieren
oder per software kann man die anwendung fest an einen core binden.
Hallo Peter II,
ich habe in der Tat ein AMD Dualcore System(Athlon X2-BE2350).
Allerdings driftet der Timer auch auf meinem anderen XP-Rechner mit
Intel T2300 Prozessor.
Viele Grüße,
Albert
Hallo Albert,
dein Code funktioniert bei mir so wie er soll ohne Drift, während bei
dir das offensichtlich der Fall ist. Woher das kommt kann ich nicht
sagen. Hier läuft ein ein Core2Duo unter W7 x64, kompiliert wurde mit
VS2010.
Gruß,
Reinhard