Hallo,
mir sind auch einige Sachen bei deinem Code aufgefallen.
Du behandelst ja das "DataReceived"-Event des SerialPorts, welches in einem anderen Thread (z.B. aus einem Thread-Pool) aufgerufen werden kann. In dem Ereignishandler jedoch benutzt du dann die Methode ReadTo(String), die wie die anderen Read()-Methoden allerdings blockieren kann (solange, dis die angegebene Zeichenfolge gelesen wurde).
Aber was passiert, wenn zuerst z.B. nur ein einziges Byte ankommt, welches nicht die angegebe Trennungszeichenfolge enthält? In dem Fall würde ja die ReadTo()-Methode blockieren. Wenn danach allerdings weitere Daten ankommen, müsste das DataReceived-Event wieder ausgelöst werden, allerdings würde sich der andere Thread immer noch in dem Eventhandler befinden. Nun könnte es z.B. passieren, dass ein weiterer Thread aus dem Threadpool verwendet wird, um das DataReceived-Event auszulösen, wobei wiederrum die ReadTo()-Methode des SerialPorts aufgerufen wird, was zu Fehlern führen könnte.
Man müsste sich den Quellcode der SerialPort-Klasse genauer ansehen, um nachvollziehen zu können, was in solchen Situationen passieren könnte, weshalb es vermutlich einfacher wäre, es gar nicht erst dazu kommen zu lassen und z.B. einfach einen anderen Thread zu starten, der in einer Schleife die ReadTo-Methode aufruft (so wie es auch in den MSDN-Beispielen zum SerialPort dargestellt ist).
Ein anderer Punkt ist, dass du eine Variable in der Form dazu benutzt, den empfangenen String zu speichern und dann im GUI-Thread wieder auszulesen. Normalerweise aber sollte man die empfangenen Daten im Aufruf der Methode übergeben, denn nur dafür werden sie ja gebraucht. Ansonsten kann es beispielsweise zu Race Conditions kommen, wenn man nicht entsprechend synchronisiert. Hier wird zwar durch die Verwendung von "Invoke" (statt "BeginInvoke") sichergestellt, dass "s" nicht vom Lesethread überschrieben werden kann, solange der GUI-Thread noch mit der Ausführung der "InListeEintragen"-Methode beschäftigt ist; trotzdem sollte man soetwas vermeiden.
Hier ein Beispiel für einen separaten Lesethread:
Private serialPortReadThread As Thread
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) _
Handles MyBase.Load
SerialPort1.Open()
'Lesethread starten
serialPortReadThread = New Thread( _
Sub()
ReadSerialPort(SerialPort1)
End Sub)
serialPortReadThread.Start()
End Sub
Private Sub ReadSerialPort(sp As SerialPort)
Try
Do While True
Dim s As String = sp.ReadTo(ChrW(13))
Invoke( _
Sub()
InListeEintragen(s)
End Sub)
Loop
Catch ex As ThreadInterruptedException
' Thread wurde interrupted.
End Try
End Sub
Private Sub InListeEintragen(s As String)
ListBox1.Items.Add(s)
If Not ok Then
SendZwei(s)
End If
End Sub
Private Sub Form1_FormClosed(sender As System.Object, e As _
System.Windows.Forms.FormClosedEventArgs) Handles MyBase.FormClosed
' Lesethread unterbrechen, sodass er beendet wird
serialPortReadThread.Interrupt()
End Sub
Beitrag wurde zuletzt am 30.06.12 um 20:14:03 editiert. |