PurgeComm returned nie
-
Hallo Leute.
Ich habe eine Anwendung die ein Wahnsinniger geschrieben hat - naja, ganz so schlimm ist es nicht.
Es wird ein COM Port für Read/Write geöffnet per CreateFile und ein Thread gestartet der auf Input warten und diesen dann quittiert, etc. Diese Kommunikation läuft sauber.
Wenn nun aber der User den Thread abbricht (durch schließen des Fensters) dann hängt die Anwendung (zumindest auf einigen Rechnern - auf meinem Development Rechnern leider nicht reproduzierbar, beim Kunden auf unterschiedlichen Geräten aber leider schon).
Das Problem ist dabei, dass ich im Destruktor des Fensters den COM Port schließen will. Dazu mache ich ein PurgeComm und danach ein CloseHandle.
Welche Gründe kann es geben, dass ein PurgeComm bzw. ein CloseHandle (wenn ich PurgeComm einfach nicht aufrufe) ewig hängt. Die Funktion returned einfach nie.
PurgeComm mit PURGE_?XABORT sollte ja sofort returnen. Ich weiss, das sind wenige Infos - aber vielleicht könnt ihr ja mal ins blaue raten woran es theoretisch liegen könnte dass Operationen auf dem COM Port nicht returnen (in dem gestarteten Thread klappt die Kommunikation über den COM Port auch ohne Probleme und wenn der Thread nach Beendigung der Übertragung den Port schließt funktioniert auch alles einwandfrei).
Auf den Geräten laufen überall Windows XP SP2 bzw. auch manchen SP3.
-
Fragen wiir uns zuerst einmal, warum er ein "PurgeComm" macht.
Die Antwort hieraus ist noch ziemlich einfach: Wenn "CloseHandle" aufgerufen wird, so werden alle Daten *zwangsweise* auf dem COM-Port geschrieben. Dies kann jetzt zu erheblichen Problemen führen, wenn z.B: Hardware-Handschake eingestellt ist und die Gegenstelle nicht antwortet. So kann es vorkommen, dass "CloseHandle" hängen bleibt, bis die Daten geschrieben wurden.Deshalb hat vermutlich der Programmierer gedacht, dass er "PurgeComm" aufruft um dieses Problem zu vermeiden. Das ist aber ein Trugschluss, da es trotzdem noch vorkommen kann, dass Daten zum senden im Buffer des seriellen Bausteines stehen. Und "CloseHandle" wartet darauf, dass *diese* Daten übertragen wurden!
Also, meine Vermutung: Der Thread bleibt in "CloseHandle" stehen...
Um das Probkenm zu lösen, würde ich Folgendes Vorschlagen:
- Versuche es bei Dir nachzuvollziehen; verwende dazu ein *voll* bestücktes Kabel!
- Es müsste sich raltiv einfach nachvollziehen lassen, wenn Du Hardware-Handshake aktivierst (oder auch rein auf die CTS/DTR/RTS-Signale achtest).Meine Lösung (hab es aber selber noch nicht probiert:
- *Vor* dem CloseHandle setze die Properties der Schnittstelle auf "ohne Handshake". Dann wartet zwar "CloseHandle" immer noch auf das schreiben der Daten, aber die Daten werden sofort geschrieben, da ja auf niemanden gewartet wird.
Leider lässt sich dies nicht anders lösen...
Zum Glück hat aber die Implementierung den "Fehler", dass er beim Ändern der Settings *nicht* auf das schreiben der Daten wartet
dies hat zwar auch als Nebeneffekt, dass, wenn man nach einem "WriteFile" die Settings ändert, ein Teil mit den alten Settings und ein Teil mit den neuen Settings geschrieben wird (nein, WriteFile kommt nicht erst zurpck, wenn die Daten übertragen wurden!)Hoffe das Hilft Dir...
-
Hallo.
Macht Sinn was du sagst. Werde das mal testen gehen.
Aber er bleibt auch im PurgeComm hängen - was ja eigentlich nicht sein dürfte. Ursprünglich wurde es nur mit PURGE_TXCLEAR|PURGE_RXCLEAR aufgerufen, ich habe das dann auf ein PURGE_RXABORT|PURGE_TXABORT geändert (ohne Erfolg).
Aber das mit dem Hardware Handshake würde natürlich auch das unterschiedliche Verhalten auf unterschiedlichen Rechnern erklären.
Auf jedenfall habe ich etwas um damit arbeiten zu können.
Könnte es theoretisch auch sein dass der Thread der für die Kommunikation über den COM Port verantwortlich ist einen exklusiven Lock auf dem Handle hat? Ohne dass er es jetzt explizit anfordert sondern zB indirekt über ein wartendes ReadFile oder dergleichen?
Danke

-
Shade Of Mine schrieb:
Könnte es theoretisch auch sein dass der Thread der für die Kommunikation über den COM Port verantwortlich ist einen exklusiven Lock auf dem Handle hat?
Verstehe ich jetzt nicht ganz... wer soll denn da was locken?
-
Hallo.
Ich hatte heute ein Notebook da bei dem sich der Fehler reproduzieren lies.
Das Problem war, dass im Thread ein WaitCommEvent() aufgerufen wurde - das ewig geblockt hat da nie ein Event auf dem COM Port aufgetreten ist. Ich habe auch keine Moeglichkeit gefunden ein Event ala SetEvent oder aehnliches an den COM Port abzuschicken und das blocken so zu beenden.
Solange nun der Thread A auf ein WaitCommEvent gewartet hat, hat jeder Zugriff auf den Port (sei es CloseHandle, SetCommMask, PurgeComm,...) ebenfalls ewig geblockt.
Habe das nun durch ein nicht blockendes ReadFile ersetzt und nun laeuft es ohne Probleme.
Was mich aber interessieren wuerde:
warum blockt WaitCommEvent auf manchen Geraeten ewig und auf manchen nicht? Die Software lief frueher unter Windows 98 SE ohne Probleme. Hat sich da etwas geaendert? Und vorallem: wie beende ich ein warten auf ein WaitCommEvent?Danke jedenfalls

-
Shade Of Mine schrieb:
Und vorallem: wie beende ich ein warten auf ein WaitCommEvent?
dazu musste 'overlapped' i/o benutzen. WaitCommEvent bekommt dann eine overlapped-struct, in der ein event-objekt steckt, dass du z.b. manuell setzen kannst, um WaitCommEvent auszulösen. alternativ ginge auch ein nachträgliches verändern der 'comm mask'. das weckt WaitCommEvent auch auf.
jedenfalls , ein non-overlapped WaitCommEvent wartet ewig, aber vielleicht gibts ja irgendwelche undokumentierten tricks (vielleicht das handle schliessen??).

-
~fricky schrieb:
alternativ ginge auch ein nachträgliches verändern der 'comm mask'. das weckt WaitCommEvent auch auf.
Das dachte ich mir, aber es hat nicht funktioniert.
Ein SetCommMask(port, 0) hat ebenfalls ewig geblockt.
Frueher wurde es aber scheinbar so gemacht, da der Call im Code auskommentiert drinnen stand...jedenfalls , ein non-overlapped WaitCommEvent wartet ewig
Finde ich etwas strange, dass man nichtmal ein timeout angeben kann - aber OK, ich habe es ja jetzt ueber ReadFile geloest, das alle 2 Sekunden mal nachsieht ob Daten da sind. Nicht sehr schoen aber funktioniert wenigstens...
-
Shade Of Mine schrieb:
~fricky schrieb:
alternativ ginge auch ein nachträgliches verändern der 'comm mask'. das weckt WaitCommEvent auch auf.
Das dachte ich mir, aber es hat nicht funktioniert.
Ein SetCommMask(port, 0) hat ebenfalls ewig geblockt.das funzt ja auch nur mit overlapped I/O.
Shade Of Mine schrieb:
jedenfalls , ein non-overlapped WaitCommEvent wartet ewig
Finde ich etwas strange, dass man nichtmal ein timeout angeben kann
naja, mit overlapped I/O hat man doch alle möglichkeiten. aber stimmt schon, das handling der seriellen schnittstelle ist unter windows unnötig kompliziert. ich weiss auch nicht, was m$ geritten hat, als sie sich sowas ausgedacht haben.
