Hallo,
ich habe Software entwickelt die einen Teststand über ein GUI steuert.
Der zeitkritische Teiltest funktioniert auf manchen PC nicht immer. Auf
beiden PC ist Win xp installiert. Es laufen mehrere Threads. Der PC mit
einem schnelleren Prozessor macht Probleme. Kommuniziert wird mit einem
Funkmodul, dem ein FTDI Chip vorgeschaltet ist.
Also ich frag einfach mal, da ich seit 1,5 Wochen nach einer Lösung
suche. Hoffe einfach mal auf einen Tipp, der mich in die richtige
Richtung leitet.
Vielen Dank schon mal.
Max schrieb:> Es laufen mehrere Threads. Der PC mit> einem schnelleren Prozessor macht Probleme.
klingt stark nach einen Threadproblem. Überprüfe alle zugriffe auf
globale Variablen/Daten.
Bei diesem Teststand wird über RS232 ein Mc angesteuert und über USB
eine Platine zur Farbanalyse. Zudem wird mit dem Prüfling über Funk
kommuniziert, wozu das Funkmodul genommen wird. Dazu steht ihm ein
Thread bereit, der die Eingangsdaten des FTDI-Chip (über einen Treiber,
der direkt auf die USB-Schnittstelle zugreift mit Hilfe einer
Seriennummer (D2XX-Treiber)) in einen Eingangspuffer schreibt. Ansonsten
stellen alle anderen Threads , der in Vb.net geschriebenen Software,
eine Instanz der Klasse Backgroundworker dar, also dem Backgroundworker
steht auch ein Thread zur Verfügung und dieser Klasse steht in vb.net
einige Funktionalität bereit.
Der zeitkritische Vorgang, bei dem mit dem Prüfling kommuniziert wird
(Anmeldung), findent in einem Backgroundworker statt.
Was bedeuted, dass ich den FTDI überfahre?
noch ein Nachtrag. Unter win7 funktioniert diese Software wiederum mit
einem mind. ebenso schnellen, wie der PC auf dem sie nicht unter win xp
funktioniert.
Peter II schrieb:> klingt stark nach einen Threadproblem. Überprüfe alle zugriffe auf> globale Variablen/Daten.
Wieso darauf überprüfen? Weiß nicht was ich jetzt tun soll.
du hast also 1,5 Wochen gesucht,
die suche ergab bisher : "es funktioniert nicht"..
ich glaub du suchst einfach falsch
lass z.B. mal jeden Thread mitloggen was er/wann macht...
(wenns zeitkritisch ist, nimmt man keine threads ;-)...
Kommunizierst du aus mehreren Threads mit dem Funkmodul bzw. mit einer
seriellen Schnittstelle?
Falls ja fang neu an. Überlege dir welcher Thread für was zuständig ist.
Dann mache saubere Schnittstellen zwischen den Threads. Synchronisiere
die Schnittstellen.
Robert L. schrieb:> (wenns zeitkritisch ist, nimmt man keine threads ;-)...
... und vor allem auch keinen Windows XP oder 7 PC. Du kannst nie wissen
was der zum Ausführungszeitpunkt alles macht.
Max schrieb:> Peter II schrieb:>> klingt stark nach einen Threadproblem. Überprüfe alle zugriffe auf>> globale Variablen/Daten.>> Wieso darauf überprüfen? Weiß nicht was ich jetzt tun soll.
man muss jeden Zugriff auf Variablen (oder Objekte) Threadsicher machen.
Das heist das immer nur ein Thread darauf zugreifen kann.
Wenn du z.b. 2. Threads hast die eine Variabel hochzählen
i = i + 1;
dann ist du hier schon einen Fehler, weil der zugriff nicht atomar ist.
Du verzählst dich damit.
Robert L. schrieb:> du hast also 1,5 Wochen gesucht,> die suche ergab bisher : "es funktioniert nicht"..>>> ich glaub du suchst einfach falsch> lass z.B. mal jeden Thread mitloggen was er/wann macht...>>>> (wenns zeitkritisch ist, nimmt man keine threads ;-)...
was versteht man denn darunter? System.Diagnostics - aufzeichnen und
auslesen? Oder Software nutzen wie SmartInspect?
Stehen nur Rechner mit win xp und 7 zur Verfügung.
Max schrieb:>> ich glaub du suchst einfach falsch>> lass z.B. mal jeden Thread mitloggen was er/wann macht...> was versteht man denn darunter? System.Diagnostics - aufzeichnen und> auslesen? Oder Software nutzen wie SmartInspect?
siche ich nicht als sinnvoll an. Mit dem System.Diagnostics änderst du
das Zeitverhalten der Threads und der fehler kann schon nicht mehr
auftreten.
Zeige doch einfach mal etwas quellcode, wichtig ist der Thread und der
Teil der die Daten dann weiterverarbeitet.
Beschreib doch mal die Aufgaben der "Backgoundworker". Gibt es da
Überschneidungen bei der Nutzung von den Daten oder Resourcen?
Du beschreibst auch nicht die Art der Fehlfunktion. Beendet sich das
Programm unplanmäßig? Stimmten die Versionen der Frameworks die VB nutzt
überein?
Wie sieht es mit deiner Fehlerbehandlung aus. Ignorierst Du Fehlercodes
und Exceptions, sodass Du Probleme gar nicht mit bekommst?
Du musst schon detaillierter dein Problem schildern.
Grüsse
> Also ich frag einfach mal
Unter Windoss 3.1 konnte man noch sehr gut echtzeitfähige
Anwenderprogramme schreiben, denn die Interrupts standen den
Anwenderprogrammen zur Verfügung und es gab nichts höherpriorisiertes.
Seit dem Festplattencache vcache.386 hatte man Probleme, weil das per
NMI jeden Prozess bis zur Ewigkeit ausbremsen konnte, damit war Win95
nicht mehr für Echtzeitanwendungen geeignet, es sei denn, man schmiss
das Cache raus.
Wenn man überhaupt auf Interrupts reagieren muss, muss man heute Device
Treiber schreiben, die im höherpriorisierten Kernel sitzen. Das geht
unter Windows XP noch.
Mit Windows 7 ist auch das unmöglich geworden, du müsstest deine Treiber
signieren, das Betriebssystem ist somit vollkommen unbrauchbar für
Echtzeitexperimente.
Unter Linux sieht es übrigens nicht besser aus.
Manche Leute nennen das Fortschritt.
MaWin schrieb:> Wenn man überhaupt auf Interrupts reagieren muss, muss man heute Device> Treiber schreiben, die im höherpriorisierten Kernel sitzen. Das geht> unter Windows XP noch.
das ganze ist zwar schön zu wissen, spielt hier aber überhaupt keine
rolle.
> Mit Windows 7 ist auch das unmöglich geworden, du müsstest deine Treiber> signieren, das Betriebssystem ist somit vollkommen unbrauchbar für> Echtzeitexperimente.
auch das wollte niemand wissen.
Es will eine FTDI Chip abfragen, dieser liefert so langsam daten, das
das schon vor 10Jahren auf jeden PC funktioniert hat.
Hier wird nur ein Fehler in der Anwendungssoftware sein, es muss kein
Treiber geschrieben werden und auch nicht auf Interrupts reagiert
werden. Denn der Treibe vom FTDI liefert ein event.
Also naja, ist jetzt eine Menge. bgw_funkmodul_DoWork unterscheidet 2
modi des Funkmoduls. im 2. jeweils was durch eine boolsche Variable
unterschieden wird, werden alle Daten durchgelassen.
Der Backgroundworker deligiert nach dem Finden eines Zeichen an die Sub
Work data.
Der Thread reiveData schreibt einfach in einen Buffer, was ein Bytearray
darstellt.
Der Testvorgang findet in einem Backgroundworker statt und ist hier
nicht darstellt.
Prinzipiell ist das jetzt schon viel Code. Falls das erschlägt oder ich
das anders, lieber erklärend darstellen soll, mache ich das gerne.
Auch könnte ich den Ausschnitt des Testvorgangs darstellen.
1
Private WithEvents Funkmodul As New FTDI() 'FTDI Bibliothek
2
3
'Delegate für das Funkfunkmodul
4
Private Delegate Sub Delegat_Funkmodul_Data_Received(ByVal dIN As String)
5
Private Funkmodul_Data_Received As New Delegat_Funkmodul_Data_Received(AddressOf Funkmodul_Work_Data)
naja, der code ist so leider sehr schwer lesbar. Bitte als Anhang.
Aber die ganzen
System.Threading.Thread.Sleep(3)
sind schon mal falsch. Es gibt überhaupt keinen Grund zu warten. Du
bekommst einen event wenn neue Daten reinkommen. Warum sollte man extra
noch warten?
Max schrieb:> Also das Funkmodul macht "auch" Probleme und funktioniert bei 2> aufeinanderfolgenden Testvorgängen meist nicht.
Wenn kein ausreichendes Zeitfenster ist, alle Pakete GESUND zu
empfangen, ist Dein Zug schon abgefahren. Entwerder behilfst Du Dir mit
Werten aus dem Cache oder wirfst diese falschen Ergebnisse rechtzeitig
weg.
nächsten fehler:
> Funkmodul.GetRxBytesAvailable(count)>> If count > 0 Then> Funkmodul.Read(din, 1, bytesread)
was ist wenn mal mehr als 1 Zeichen kommt? Dann liest du nur das erste
zeichen. du musst alles lesen was da ist!
MaWin schrieb:> Unter Linux sieht es übrigens nicht besser aus.
Doch, sogar deutlich besser. Für Linux gibt es reichlich
Erweiterungen/Modifizierungen:
- RTLinux (LinuxCNC läuft darunter)
- RTAI
- LibeRTOS
- Xenomai
- usw.
Da kann man sich nach Belieben austoben :-)
oszi40 schrieb:> Wenn kein ausreichendes Zeitfenster ist, alle Pakete GESUND zu> empfangen, ist Dein Zug schon abgefahren. Entwerder behilfst Du Dir mit> Werten aus dem Cache oder wirfst diese falschen Ergebnisse rechtzeitig> weg.
das habe ich nicht verstanden. Welche Werte und wie bekomme ich die?
Die Pausen habe ich wegen der Systemauslastung gemacht, aber lasse ich
gerne weg.
Code kommt gleich in einem Anhang.
Max schrieb:> Die Pausen habe ich wegen der Systemauslastung gemacht, aber lasse ich> gerne weg.
dann arbeitest du nicht mit events. Schau dir die doku von FTDI an.
Normalerweise brauchst du nicht mal einen Backgrundworkder zum einlesen.
Peter II schrieb:>> Funkmodul.GetRxBytesAvailable(count)>>>> If count > 0 Then>> Funkmodul.Read(din, 1, bytesread)
ist eine Schleife, die solange Daten da sind jeweils 1 Byte in den
Buffer schreiben. Den Fehler verstehe ich nicht.
klar hier ist das Problem
> Private Sub Funkmodul_DataReceived()> While True>> Funkmodul.GetRxBytesAvailable(count)>>> End While
das ist der falsche weg. Entwedewr macht man einfach einen
while true
Funkmodul.Read(din, 1, bytesread)
end while
oder man arbeitet mit GetRxBytesAvailable und events. So wie du es
gemacht hast ist es aber falsch.
Max schrieb:>>> If count > 0 Then>>> Funkmodul.Read(din, 1, bytesread)>> ist eine Schleife, die solange Daten da sind jeweils 1 Byte in den> Buffer schreiben. Den Fehler verstehe ich nicht.
ich kann zwar nicht VB aber wo ist da eine Schleife? das ist eine IF
abfrage und keine schleife.
Aber die Prozedur ist sowieso falsch, siehe vorherigen beitrag.
Also probiere das gleich aus.
@ Peter: ist doch in einer while(true)-Schleife und fragt dann if ab.
Und was mich durchgehend beschäftigt, wenn hier der Fehler liegt. Wieso
funktioniert das dennoch an 2 PCs und an einem nicht, denn daraus kann
ich mir keinen Reim machen.
Threading.Thread.Sleep(1)
wow, das ist EINE GANZE MILLISEKUNDE !
(ich dachte mir es wäre zeitkritisch ??!)
;-)
der code ansonsten ist vermutlich nicht SOO daneben (sonst würde er ja
überhaupt nicht funktionieren)
ich würde als erstes mal "cirtical sections" machen..
immer dort wo du auf "globale" Sachen zugreifst...
also z.b. um den teil:
Funkmodul_fifo(Funkmodul_schreibe_pointer) = din(0)
Funkmodul_schreibe_pointer += 1
If Funkmodul_schreibe_pointer = UBound(Funkmodul_fifo) +
1 Then Funkmodul_schreibe_pointer = 0
usw.
Max schrieb:> @ Peter: ist doch in einer while(true)-Schleife und fragt dann if ab.
ja hatte ich übersehen, ich bin davon ausgegangen das das die Sub nur
bei einem event vom FTDI aufgefufen wird.
> Und was mich durchgehend beschäftigt, wenn hier der Fehler liegt. Wieso> funktioniert das dennoch an 2 PCs und an einem nicht, denn daraus kann> ich mir keinen Reim machen.
das ist bei Softwarefehler immer der Fall, mal geht mal nicht. Ändere
ist mal das auslesen und enterne die sleeps. Die CPU lasst darf dabei
nicht steigen! Wenn doch hast du noch einen fehler. Dann Teste noch mal.
>Die CPU lasst darf dabei>nicht steigen
doch das wird sie,
ein kern wird 100% ausgelastet:
warum sollte sie auch nicht tun???
die sleep sind (prinzipiell) nicht sooo falsch, ...
nur 1 Millisekunde warten, nach jedem Byte ist etwas "lang"
Robert L. schrieb:> doch das wird sie,> ein kern wird 100% ausgelastet:> warum sollte sie auch nicht tun???
weil man nur ein Read macht, diese Read blockiert bis daten ankommen und
bracuht dabei keine CPU zeit.
> die sleep sind (prinzipiell) nicht sooo falsch, ...> nur 1 Millisekunde warten, nach jedem Byte ist etwas "lang"
doch ist es. Sleep hier absolut falsch.
Also der Änderungsversuch hat nichts gebracht. Mache die ms im
receiveThread noch weg.
Nochmals @ Peter: zu dem Softwarefehler. Auf den anderen Pc's gibt es
keine Fehler, der Test wurde an verschiedenen Tagen mehrmals
wiederhohlt. Von diesem Gedanken ausgehend habe ich halt versucht dem
Problem auf den Grund zu gehen.
Eure Vorschläge neheme ich tausend dankend an und probiere alles aus,
doch wieso das einen Unterschied ergibt? Wird es an den anderen Pc's
dann möglicherweise nicht mehr laufen und ich brauche 2
Softwareversionen?
Max schrieb:> Eure Vorschläge neheme ich tausend dankend an und probiere alles aus,> doch wieso das einen Unterschied ergibt? Wird es an den anderen Pc's> dann möglicherweise nicht mehr laufen und ich brauche 2> Softwareversionen?
nein nur eine die funktioniet. Hat der andere PC die gleiche CPU anzahl?
Max schrieb:> Also der Änderungsversuch hat nichts gebracht. Mache die ms im> receiveThread noch weg.
dann zeige mal bitte wieder den code (als anhang) damit man sieht was du
gemacht hast.
8 kerne a 3,2 ghz und und 4 a 2,4 ghz funktioneriert es. und bei 4 a 2,4
ghz funktioniert es.
While True
Funkmodul.GetRxBytesAvailable(count)
Funkmodul.Read(din, 1, bytesread)
Funkmodul_fifo(Funkmodul_schreibe_pointer) = din(0)
Funkmodul_schreibe_pointer += 1
If Funkmodul_schreibe_pointer = UBound(Funkmodul_fifo) + 1
Then Funkmodul_schreibe_pointer = 0
End While
passt so?
das
> Funkmodul.GetRxBytesAvailable(count)
kann auch weg
> und die 3 ms weg bei dem Backgroundworker
das kannst erstmal bleiben, sollte aber auch später entfernt werden. Und
zwar durch ein event
http://msdn.microsoft.com/de-de/library/system.threading.eventwaithandle.aspx
dann braucht man keine wartezeit mehr.
Das:
While True
Funkmodul.GetRxBytesAvailable(count)
...
ist auf einem Multithreading System völlig daneben.
Da die GetRxBytesAvaiable Funktion zu 99,99% der zeit eben keine Bytes
zu lesen hat wird die Schleife mit voller Geschwindigkeit ausgeführt und
erzeugt ein Haufen leere Last.
Hier muss man (wie auch immer in basic) sich durch einen Event rufen
lassen oder einen blockierenden Receive Aufruf mit einem Timeout machen.
Das gibt dem Betriebssystem die Möglichkeit die Rechenzeit abzugeben.
>weil man nur ein Read macht, diese Read blockiert bis daten ankommen und>bracuht dabei keine CPU zeit.
tut es das?
ich weiß es nicht, meine Antwort war eher "allgemein"
Funkmodul.Read(din, 1, bytesread)
die Funktion schaute für mich (auf den 1. blick) NICHT blockierend aus..
ist sie aber anscheinend (allerdings mit Default timeout von 500ms???)
d.h. man sollte hier wohl auf exception achten (vielleicht ist dass das
problem?)
WENN man eine blockierende funktion verwendet, DANN ist das weglassen
vom sleep sicher ok usw. usw.
die blockierende funktion sollte dann aber (trotzdem) ein timeout haben
(z.b. 1 sekunde)
um zwischendurch prüfen zu können ob man den thread gegebenenfalls
korrekt zu beenden hat....
Robert L. schrieb:> die Funktion schaute für mich (auf den 1. blick) NICHT blockierend aus..> ist sie aber anscheinend (allerdings mit Default timeout von 500ms???)> d.h. man sollte hier wohl auf exception achten (vielleicht ist dass das> problem?)
eigentlich sind alle read funktionen standardmäßig blockierend.
> die blockierende funktion sollte dann aber (trotzdem) ein timeout haben> (z.b. 1 sekunde)> um zwischendurch prüfen zu können ob man den thread gegebenenfalls> korrekt zu beenden hat....
nicht zwingend. Dafür kann man auch einfach das Handle schließen und
damit kommt das Read mit einem fehler zurück.
>eigentlich sind alle read funktionen standardmäßig blockierend.
ja, in VB (.net) vielleicht..
das kann schon sein..
kenn ich nicht..
ich bin wie gesagt, davon ausgegangen, dass die funktion einfach 0
zurück liefert wenn keine daten vorhanden sind..
in der Doku steht da auch "nix genaues"... finde ich..
Robert L. schrieb:> ja, in VB (.net) vielleicht..> das kann schon sein..> kenn ich nicht..
wo denn nicht? In C ist es auch der Fall. In Perl auch. Welchen Read ist
denn standardmäßig nicht blockierend?
1. bester
http://arduino.cc/en/Serial/read
Returns the first byte of incoming serial data available (or -1 if no
data is available) - int
;-)
(das code beispiel dort ist allerdings schlecht..)
kleiner nachtrag:
das REad um das wir hier diskutieren, schaut nicht nach dem
"serialPort.Read" von VB.net aus
ich halte es weiterhin für möglich, dass es nicht blockierend ist..
bytesread ist nämlich 0
beim serialPort.Read, wäre der 3. parameter aber die anzahl zu lesender
byte.. ?!
Robert L. schrieb:> ich halte es weiterhin für möglich, dass es nicht blockierend ist..> bytesread ist nämlich 0
bytesread ist der rückgabewert, wie viele zeichen gelesen wurden. Und ja
Read blockiert nicht wenn das Handle geschlossen wurden oder man 0
zeichen lesen will.
meine antwort bezog sich darauf:
>bytesread ist der rückgabewert,
der 3. Parameter ist NICHT
> wie viele zeichen gelesen wurden
veilleicht ist es ja non-blocking wenn man den 3. parameter mit 0 füllt
.., was weiß ich bei 2 zeilen doku..
Viel sinnvoller als die Zeit mit dem PC zu verplempern waere die
zeitkritischen Dinge auf einen Controller auszulagern und den PC nur als
Control- & Visualisierer zu verwenden.
Viktor N. schrieb:> Viel sinnvoller als die Zeit mit dem PC zu verplempern waere die> zeitkritischen Dinge auf einen Controller auszulagern
es gibt hier überhaupt nichts zeitkritisches.