Forum: PC-Programmierung Timing mit einer Windows-UI Anwendung


von *guest* (Gast)


Lesenswert?

Ich Programmiere Mess-Anwendungen mit einer grafischen 
Benutzeroberfläche mit CVI von National Instruments. Das Programm muss 
alle 500ms ein Heartbeat von sich geben, was duch nichts gestört werden 
darf. Also auch wenn ich das Anwendungsfenster verschiebe oder sonst 
etwas tue, es soll exakt alle 500ms ausgeführt werden.

Bisher benutze ich aus CVI eigens dafür bereitgestellte 
Thread-Funktionen und parametriere das Thread-Pool mit Eigenschaften wie 
Priority etc.

GEht sowas auch direkt in C zu schreiben? Ohne fertige Funktionen von 
CVI? Wenn ja, wie geht das?

von ... (Gast)


Lesenswert?

*guest* schrieb:
> exakt alle 500ms ausgeführt werden

Also "exakt" und "Windows" passt nicht wirklich zusammen.

*guest* schrieb:
> GEht sowas auch direkt in C zu schreiben?

Selbstverstänlich, Threads kann man auch in C benutzten. Siehe:
http://msdn.microsoft.com/en-us/library/kdzttdcb.aspx
http://msdn.microsoft.com/en-us/library/ms686277%28v=VS.85%29.aspx

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Abgesehen davon, daß eine Windows-Anwendung keine Echtzeitanforderungen 
erfüllt, ist es mit der Win32-API sehr wohl möglich, Dinge im 
500msec-Takt durchzuführen, auch wenn gerade irgendwelche Fenster bewegt 
werden.

Dazu sollten die timingkritischen Anteile der Anwendung in einem eigenen 
Thread laufen - und Threads unterstützt die Win32-API seit 1993.

Du musst allerdings berücksichtigen, daß die Granularität des 
Windows-Schedulers nicht genauer als auf 1 msec hinzubekommen ist, 
standardmäßig liegt sie sogar bei 10 msec.

(Das lässt sich mit der Win32-API-Funktion timeBeginPeriod aus der 
Multimedia-API allerdings leicht ändern).

Die Multimedia-API-Funktionen bieten auch die Möglichkeit, eine 
Callback-Funktion von einem vom System verwalteten Thread regelmäßig 
aufrufen zu lassen, das dürfte für Deine Anwendung möglicherweise die 
einfachste Lösung sein.

Dafür ist die Funktion timeSetEvent zuständig:
http://msdn.microsoft.com/en-us/library/dd757634(v=vs.85).aspx

von ... (Gast)


Lesenswert?

Achso, Threadpools gibts in C natürlich auch. Aber das wäre wohl mit 
Kanonen auf Spatzen :)
http://msdn.microsoft.com/en-us/library/ms682456%28v=VS.85%29.aspx

Falls es auch C++ sein darf:
http://www.boost.org/doc/libs/1_47_0/doc/html/thread.html

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

*guest* schrieb:
> ein Heartbeat

Normal ist es aber doch eher das mindestens alle 500ms ein Heartbeat 
erfolgen muss... wozu will man so was den genau alle 500ms haben?

von *GAST* (Gast)


Lesenswert?

... schrieb:
> Aber das wäre wohl mit
> Kanonen auf Spatzen :)

ähm so fühle ich mich grad schon ein bisschen... danke erstmal für all 
die Hinweise! Also wäre für mich erstmal die Multimedia-API-Funktion das 
beste?

Läubi .. schrieb:
> Normal ist es aber doch eher das mindestens alle 500ms ein Heartbeat
> erfolgen muss...

Ja, das reicht natürlich aus. Ändert das etwas an meinem Vorgehen? Oder 
weiterhin Multimedia-API?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

*GAST* schrieb:
> Also wäre für mich erstmal die Multimedia-API-Funktion das
> beste?

Ob sie das beste ist, kann ich Dir nicht sagen, es hängt schließlich 
auch davon ab, auf welche Art und Weise die vom System zyklisch 
aufgerufene Funktion sein "Heartbeat" von sich geben muss. Wohin soll 
das auf welchem Wege gehen?

Berücksichtigen musst Du halt die Aspekte der Threadsicherheit, d.h., 
Objekte, die in der Callbackfunktion verwendet werden, sollten tunlichst 
nicht von irgendwas anderem noch "befummelt" werden.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

*GAST* schrieb:
> Ja, das reicht natürlich aus. Ändert das etwas an meinem Vorgehen? Oder
> weiterhin Multimedia-API?

Nimm einen "normalen" Thread, setz den Timeout auf 400ms und selbst mit 
den +/-10ms und einem ungnädigem Sceduler solltest du auf der sicheren 
Seite sein.

von *guest* (Gast)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Wohin soll
> das auf welchem Wege gehen?

das ganze geht über den CAN-Bus an verschiedene CAN-Module. Ich habe da 
bis jetzt eine einfache c-Funktion, die ich dann immer aus dem Thread 
aufrufen müsste. Die Funktion an sich kümmert sich dann um das Absenden 
des Frames.

Läubi .. schrieb:
> Nimm einen "normalen" Thread,

wäre das dann das mit der Multimedia-API oder wieder etwas anderes?

von Christian R. (supachris)


Lesenswert?

Nee, mit der MM-API kann man aber die "Auflösung" des Windows Task 
Schedulers von 10ms auf 1ms herunter setzen. Das wird dir nicht viel 
helfen. Im Normalfall kannst du sicher die 500ms einhalten. Aber das ist 
eben bei keinen Standard-Windows oder Standard-Linux garantiert. 
Garantieren kann man das nur mit einem Echtzeit-OS. Wenn jetzt zum 
Beispiel eine Software über solche Frickel-Treiber wie die giveio.sys 
auf einen Port zugreift, kann die durchaus den ganzen Rechner so lahm 
legen, dass der Scheduler erst irgendwann mal wieder an deinem Thread 
vorbei kommt. Zm Test kannst du ja mal zum Beispiel ein Flash-Video mit 
HW-Beschleunigung starten, was auf einem lahmen Server liegt....da 
merkst du mal, was "echt Zeit" braucht. Oder auch der McAffee 
Virenscanner....herrlich. Bei uns in der Firma legt der den auch 
Quadcores lahm, wenn man einen Ordner öffnet, wo zum Beispiel mehrere 
GB-große Zip-Files drin sind....dann is alles vorbei mit 
deterministischem Verhalten.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

*guest* schrieb:
> das ganze geht über den CAN-Bus an verschiedene CAN-Module.

Und der ist wie an den PC angeschlossen?

von *guest (Gast)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Und der ist wie an den PC angeschlossen?

Mal über eine PCI-CAN-Karte und mal über ein USB-CAN-Gerät. Dafür gibt 
es fertige Treiber und DLL's, die ich in mein Programm einbinde. Z.B. 
sind das write- oder read- Funktionen.

von Jasch (Gast)


Lesenswert?

Christian R. schrieb:
> Nee, mit der MM-API kann man aber die "Auflösung" des Windows Task
> Schedulers von 10ms auf 1ms herunter setzen. Das wird dir nicht viel
> helfen. Im Normalfall kannst du sicher die 500ms einhalten. Aber das ist
> eben bei keinen Standard-Windows oder Standard-Linux garantiert.
> Garantieren kann man das nur mit einem Echtzeit-OS. Wenn jetzt zum

Zumindest Soft-Realtime kann man mit Windows, naja, nicht machen aber 
zumindest versuchen...

> Beispiel eine Software über solche Frickel-Treiber wie die giveio.sys
> auf einen Port zugreift, kann die durchaus den ganzen Rechner so lahm
> legen, dass der Scheduler erst irgendwann mal wieder an deinem Thread
> vorbei kommt. Zm Test kannst du ja mal zum Beispiel ein Flash-Video mit
> HW-Beschleunigung starten, was auf einem lahmen Server liegt....da
> merkst du mal, was "echt Zeit" braucht. Oder auch der McAffee
> Virenscanner....herrlich. Bei uns in der Firma legt der den auch
> Quadcores lahm, wenn man einen Ordner öffnet, wo zum Beispiel mehrere
> GB-große Zip-Files drin sind....dann is alles vorbei mit
> deterministischem Verhalten.

Man kann einem Thread Prioritäten im Echtzeit-Bereich (was Windows eben 
so nennt) geben, die haben dann Vorrang vor allem anderen ausser Kernel 
soweit ich mich erinnere.

Muss man aber schon mutig sein sowas zu benutzen, wenn so ein Thread 
eine Endlosschleife hat ist es vorbei mit dem guten Windows, da passiert 
dann ausser der Endlosschleife garnix mehr. Da sollte man dann einen 
Supercomputer haben - der arbeitet ja bekanntlich eine Endlosschleife in 
3 Sekunden ab... ;-)

von Schorsch (Gast)


Lesenswert?

Wenn Du immer die 500ms Sekunden brauchst dann surfe bitte nicht im 
Internet während des Betriebs und schließe auch keine unbekannten 
USB-Geräte an o.ä.

von Peter II (Gast)


Lesenswert?

Schorsch schrieb:
> Wenn Du immer die 500ms Sekunden brauchst dann surfe bitte nicht im
> Internet während des Betriebs und schließe auch keine unbekannten
> USB-Geräte an o.ä.
jetzt übertreibt mal nicht. 500ms schafft Windows auf einem aktuellen PC 
auch wenn man im Inet surft und nebenbei noch etwas arbeitet.

Sonst würde die maus auch ständig rumruckeln. Also fang erstmal an und 
verwende eine hohe priorität.

von *guest* (Gast)


Lesenswert?

Läubi .. schrieb:
> Nimm einen "normalen" Thread

Ich hab das alles jetzt mal ein bisschen ausprobiert, aber es 
funktioniert leider nicht. CVI kennt keiner der Funktionen.

Mein Thread aus CVI sieht jetzt so aus:
1
static int CVICALLBACK Thread_Beat (void *ctrlID)
2
{                  
3
  while (1==1)
4
  {
5
    can_write(1802, 1, 0,0,0,0,0,0,0,0);
6
    Delay(0.2);
7
  }
8
  return 0;
9
}

Gibt es eine Möglichkeit es nur mit einer reinen C-Funktion ohne 
CVI-Funktionen zu machen? Das ganze läuft zu unstabil und der Programm 
hakt damit sehr stark. Es macht aber im Hintergrund eigentlich fast 
nichts, was irgendwie Rechenleistung benötigt.

von Peter II (Gast)


Lesenswert?

*guest* schrieb:
> Ich hab das alles jetzt mal ein bisschen ausprobiert, aber es
>
> funktioniert leider nicht. CVI kennt keiner der Funktionen.

welcher funktionen kennt CVI nicht?

> Mein Thread aus CVI sieht jetzt so aus:
> static int CVICALLBACK Thread_Beat (void *ctrlID)
> {
>   while (1==1)
>   {
>     can_write(1802, 1, 0,0,0,0,0,0,0,0);
>     Delay(0.2);
>   }
>   return 0;
> }
>
> Gibt es eine Möglichkeit es nur mit einer reinen C-Funktion ohne
> CVI-Funktionen zu machen?
keine ahnung, aber C kennt can_write nicht. Den Thread kann man ohne 
Probleme mit C machen.


> Das ganze läuft zu unstabil und der Programm
> hakt damit sehr stark.
und wer soll mit so einer Fehlermeldung etwas anfangen können? Was heist 
unstabil - stürzt das Programm ab? Wird nichts mehr gesendet?

von *guest* (Gast)


Lesenswert?

1
  CmtNewThreadPool (4, &pool);
2
  CmtSetThreadPoolAttribute (pool, ATTR_TP_THREAD_PRIORITY, THREAD_PRIORITY_ABOVE_NORMAL);
3
  CmtScheduleThreadPoolFunction (pool, Thread_Beat, NULL, NULL);

Damit initialisiere und starte ich den Thread in CVI. Ich wollte das 
ganze jetzt aber mit den standard-Windows-Funktionen machen, wie sie 
hier im Forum beschrieben sind.

Was soll ich z.B. bei (_beginthread) für Parameter einsetzen?

von Peter II (Gast)


Lesenswert?

*guest* schrieb:
> Was soll ich z.B. bei (_beginthread) für Parameter einsetzen?


http://msdn.microsoft.com/en-us/library/ms682453(v=vs.85).aspx

von *guest* (Gast)


Lesenswert?

Sehr gut, ich bedanke mich recht herzlich, es funktioniert.

Geht das jetzt auf genauso einfachem Wege, dass der Thread selbstständig 
alle 500ms ausgeführt wird?

Ich habe da jetzt eine Endlosschleife mit Befehlsausführung und 
anschließendem Delay(0.5).

von Christian R. (supachris)


Lesenswert?

Normalweise verwendet man da Sleep(500), das erlaubt den Scheduler einen 
Task-Wechsel. Wo kommt denn die Delay() Funktion her?

von *guest* (Gast)


Lesenswert?

Christian R. schrieb:
> Normalweise verwendet man da Sleep(500)

lol, das wusste ich nicht. Das Programm läuft damit grad zum testen. 
Positiv ist zumindest schonmal, dass die CPU-Auslastung von ~20% 
(Delay(0.5)) auf ca. 3% (Sleep(500)) gegangen ist...

Ja, die Delay-Funktion kommt wohl von CVI, wenn sie sonst keiner 
kennt...

Ist es dann so okay, einen Thread aufzurufen, mit while 1=1 in einer 
dauerschleife zu halten und die gewünschte Funktion mit Sleep(500) 
aufzurufen?
Oder wäre es noch besser, wenn "windows" den Tread alle 500ms aufruft?

von Peter II (Gast)


Lesenswert?

*guest* schrieb:
> Ist es dann so okay, einen Thread aufzurufen, mit while 1=1 in einer
> dauerschleife zu halten und die gewünschte Funktion mit Sleep(500)
> aufzurufen?
jain - das ein Thread eine entlosschleife macht ist ok. man sollte aber 
eine möglichkeit vorsehen das Programm ordentlich zu beenden.

bool stop = false;

 while (!stop)
 {
    can_write(1802, 1, 0,0,0,0,0,0,0,0);
    Sleep(500);
 }



und dann beim beenden einfach stop = false setzen und dann warten bis 
der Thread beendet ist. (WaitForSingleObject)

von Christian R. (supachris)


Lesenswert?

Bei einem MFC Programm könnte man den Timer benutzen. Ansonsten ist das 
so schon OK, wenn man natürlich wie erwähnt das Beenden noch vorsieht.

von *guest* (Gast)


Lesenswert?

Ich habe jetzt rausgefunden, dass die Umstellung von Delay() auf Sleep() 
zwar eine große Minderung der CPU-Auslastung bringt (von ca. 20% auf ca. 
3%), jedoch auch nicht mehr so stabil funktioniert. Wenn z.B. das 
Anti-Viren-Update startet verlängert sich die Heartbeat-Zeit um den 
Faktor 2-3. Mit Delay() passiert das nicht.

Ist die hohe CPU-Belastung immer ein Preis der recht zeitstabilen 
Funktionsausführung, oder bekommt man das vieleicht mit dem hier 
erwähnten Timer besser hin? Ich habe da nur überhaupt keine Ahnung, wie 
ich das realisieren kann.

von Peter II (Gast)


Lesenswert?

*guest* schrieb:
> Ich habe jetzt rausgefunden, dass die Umstellung von Delay() auf Sleep()
> zwar eine große Minderung der CPU-Auslastung bringt (von ca. 20% auf ca.
> 3%), jedoch auch nicht mehr so stabil funktioniert. Wenn z.B. das
> Anti-Viren-Update startet verlängert sich die Heartbeat-Zeit um den
> Faktor 2-3. Mit Delay() passiert das nicht.

nein, das verhalten ist auf jeden Fall nicht normal. Das Sleep sollte 
sogar genauer als das Delay sein. Ein virenscanner sollte sich hier 
überhaupt nicht einmischen können, dann er scannt ja dateien und du 
machst ja überhaupts nichts im Filesystem.

Kann es sein das dein can_write irgendwie das verhalten ändert wegen dem 
virenscanner? Keine ahnung was dabei alles gemacht wird.

lass man das senden weg und schreibe die aktuelle urzeit in eine 
logdatei, dann schau dir mal die zeiten an.

von *guest* (Gast)


Lesenswert?

Das Vieren-Programm macht keinen Scan, sondern ein Update. Ich kann aber 
auch andere Sachen tun, mit Sleep wird es immer irgendwann eine größere 
Unterbrechung geben.

Ich habe parallel immer einen CAN-Monitor laufen, der zeigt mir exakt 
die CAN-Frames an. Bei Delay(0.5) liegen die Frames ~501ms auseinander, 
bei Sleep(500) zeigt das programm ca 499ms an.

Wenn ich die CAN-Funktion auskommentiere, ist alles genau so. Es liegt 
also wirklich am Threadind und/oder der Delay-/Sleep-Funktion

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.