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?
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
*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?
... 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?
*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.
*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.
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?
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.
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.
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... ;-)
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.ä.
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.
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
staticintCVICALLBACKThread_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
return0;
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.
*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?
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?
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).
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?
*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)
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.
*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.
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