Benutzer mit den meisten Antworten
Problem - Wahrscheinlich 'threadübergreifender Zugriff' auf Controls .... (mehrere)

Frage
-
Zum Thema 'threadübergeifende Zugriffe habe ich schon einiges gelesen. Ich vermute mal, dass ich genau dieses problem habe :-(
Meine Postings drehen sich derzeit meist immer im ähnliche Problemkomplexe.
Ich habe eine Schaltung, die Daten über den CAN-Bus sendet oder empfängt und diese Daten über serielle Schnittstelle an den PC weiterleitet - immer in Paketen zu 16 Byte.
Auf dem PC existiert eine Klasse in VB.NEt genannt CANBUS, die wiederum vom COM-Port ein Ereignis bekommt wenn 16 Byte da sind.
Dann werden die Daten ausgewertet (CRC kontrollieren, etc.) und falls alles in Ordnung, ist unterscheidliche Events ausgelöst. Meist ist das ein Ereignis, wenn normale Datenpakete eingetroffen sind; es gibt aber auch Ereignisse über Fehlermeldungen u.a.
Eine einfache Testapplikation hat ein Fenster mit zahlreichen Textboxen, in denen die Daten dargestellt werden, sowie ein Datagrid.
Die Applikation instanziirt die Klasse CANBUS mit WithEvents und bekommt pormpt ein Ereignis, sobald neue Dtaen angekommen sind.
Im Ereignis-Handler werden dann die Daten in den Textboxen dargestellt und das Datagridview aktualisiert.
Zu Beginn habe ich den Kopf mittels 'CheckforIllegalThreadCalls=false' aus der Schlinge gezogen. BeimProbieren mit einzelnen Datenpaketen in grösseren Abständen ging das prima.
In 'real life' kommen die Daten aber recht schnell hintereinander. Manchmal blockiert die ANwendung nach 60-100 Paketen, manchmal läuft's aber auch lange Zeit problemlos und nur der vertikale Balken im Datagridview hängt.
Wenn ich dann die Anweisung CheckforilllegalThreadcalls=true setze oder rausnehme dann ist es ganz aus.
Ich habe schon einiges zum Thema gelesen, u.a. auch auf gssg.de und über den BackgroundWorker.
Zugegeben, das klingt alles ganz schön kompliziert. Am sympathischtesten ist mir der Backgroundworker, abe ich bin mir nicht sicher wie ich den anwenden muss.
Das Ereignis CANBUS.FrameReceived enthält grob folgende Anweisungen:
AktualisiereTExtboxen(msg) 'Date in Textboxen darstellen
AktualisiereFehlerFlags(errnr) ' Bei Fehlern Hintergrundfarbe von Labels ändern
AktualisiereDataGrid(msg) '
Wie müsste die Geschichte mit dem BackgroundWorker funktionieren ? Das Ereignis mit RunworkerCompleted scheint mir zu spät zu kommen. Und was ist mit DoWork ?
Antworten
-
Im Ereignis-Handler werden dann die Daten in den Textboxen dargestellt und das Datagridview aktualisiert.
Hallo Nico,
Du hast viele Fragen. Nur dazu: in einer Datareceived Event Routine darfst Du nicht direkt auf ein GUI Element der Form zugreifen. Diese Routine wird in einen sekundären thread angehoben. Dieses ist so direkt nicht erkennbar. Hier ein Codeausschnitt von mir, wie man damit umgeht. Die Empfangsdaten müssen zunächst in einen privat deklarierten buffer der Form geschrieben werden. Von dort kannst Du sie dann in ein GUI schreiben. (Hier RX_buffer.text TextBox)
zu deinen anderen Fragen: ich lese mir das noch einmal durch. Probiere erst einmal das hier.
schöne Grüße Ellen
P.S. Welches CAN Bus Interface benutzt Du?
Nachtrag: Hier die msdn Doku zu diesem Thema. Dasselbe, was ich schon gesagt habe uvm. ....
http://msdn.microsoft.com/de-de/library/system.io.ports.serialport.datareceived.aspx
' ------------------------------------------------------------------- ' write receive data to TextBox '-------------------------------------------------------------------- Public Sub DoUpdate(ByVal sender As Object, ByVal e As System.EventArgs) RxD_buffer.Text = readBuffer End Sub '--------------------------------------------------------------------- ' read COM Port '--------------------------------------------------------------------- Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, _ ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) _ Handles SerialPort1.DataReceived If comOpen Then Try ' reads string until .Newline property readBuffer = SerialPort1.ReadLine() 'data to form1 Me.Invoke(New EventHandler(AddressOf DoUpdate)) Catch ex As IO.InvalidDataException MsgBox(ex.Message) End Try End If End Sub
Ich benutze/ I'm using VB2008 & VB2010- Bearbeitet Ellen Ramcke Sonntag, 19. Dezember 2010 13:24 link zur msdn Doku
- Als Antwort markiert Robert Breitenhofer Dienstag, 18. Januar 2011 11:10
-
Hallo,
Zum Thema 'threadübergeifende Zugriffe habe ich schon
einiges gelesen. Ich vermute mal, dass ich genau dieses
problem habe :-(Das Problem bekommst Du z.B. dann, wenn Du versuchst
auf eine Form oder ein Steuerelement zuzugreifen, das in
einem anderen als dem zugreifenden Thread erstellt worden
ist.
Das ist z.B. dann der Fall, wenn Deine Form u. Steuerelemente
wie meist üblich im Hauptthread erstellt worden sind und ein
weiterer (separater) Thread versucht auf die Form oder eines
der Steuerelemente zuzugreifen.Meine Postings drehen sich derzeit meist immer im ähnliche
Problemkomplexe.
Ich habe eine Schaltung, die Daten über den CAN-Bus sendet
oder empfängt und diese Daten über serielle Schnittstelle an
den PC weiterleitet - immer in Paketen zu 16 Byte.Das SerialPort-Objekt, mit dem Du vermutlich Deine Zugriffe auf
die ser. Schnittstelle realisierst arbeitet asynchron, also in einem
separaten Thread. Löst SerialPort das Ereignis _DataReceived
aus, so geschieht dies in eben diesem separaten Thread und
ein direkter Zugriff auf Deine Form oder eines der darauf befindlichen
Steuerelemente ist dann, weil threadübergreifend, nicht
zulässig und muss erst mal entsprechend mit dem Hauptthread
synchronisiert werden.Auf dem PC existiert eine Klasse in VB.NEt genannt CANBUS,
die wiederum vom COM-Port ein Ereignis bekommt wenn 16 Byte
da sind.Ich vermute mal, mit "Ereignis" meinst Du das _DataReceived-
Ereignis des SerialPorts.Dann werden die Daten ausgewertet (CRC kontrollieren, etc.) und
falls alles in Ordnung, ist unterscheidliche Events ausgelöst.
Meist ist das ein Ereignis, wenn normale Datenpakete eingetroffen
sind; es gibt aber auch Ereignisse über Fehlermeldungen u.a.
Eine einfache Testapplikation hat ein Fenster mit zahlreichen
Textboxen, in denen die Daten dargestellt werden, sowie ein Datagrid.Und an dieser Stelle bekommst Du Dein Problem mit dem
threadübergreifenden Zugriff, da der im Ereignis
SerialPort_DataReceived angestossene Code eben nicht im
Hauptthread, der auch Eigentümer Deiner Form und Controls
ist, sondern in einem eigenen (separaten) Thread läuft.Die Applikation instanziirt die Klasse CANBUS mit WithEvents
und bekommt pormpt ein Ereignis, sobald neue Dtaen angekommen
sind.
Im Ereignis-Handler werden dann die Daten in den Textboxen
dargestellt und das Datagridview aktualisiert.Der Zugriff auf diese Textboxen und das DGV darf aber nicht
direkt aus dem separaten Thread (_DataReveived) erfolgen,
sondern muss erst mit dem Hauptthread synchronisiert werden.Zu Beginn habe ich den Kopf mittels
'CheckforIllegalThreadCalls=false' aus der Schlinge gezogen.Das wäre eine recht unschöne Holzhammermethode, die Du
besser nicht anwenden solltest, weil das durchaus zu Problemen
führen kann.BeimProbieren mit einzelnen Datenpaketen in grösseren
Abständen ging das prima.
In 'real life' kommen die Daten aber recht schnell hintereinander.
Manchmal blockiert die ANwendung nach 60-100 Paketen,
manchmal läuft's aber auch lange Zeit problemlos und nur der
vertikale Balken im Datagridview hängt.Irgendwann gibt es Konflikte zwischen Hauptthread und zweitem
Thread beim Zugriffen auf Deine Form bzw. Controls.Wenn ich dann die Anweisung CheckforilllegalThreadcalls=true
setze oder rausnehme dann ist es ganz aus.Dann musst Du eben "sauber" arbeiten und Deine Zugriffe
aus dem separaten Thread "threadsicher" machen.Ich habe schon einiges zum Thema gelesen, u.a. auch auf
gssg.de und über den BackgroundWorker.Der BackgroundWorker wäre eine Möglichkeit, es geht
aber auch ohne.Hier mal ein Beispiel, das den Zugriff aus zwei verschiedenen
Threads (Hauptthread und separater Thread mTH) auf ein
Label-Steuerelement zeigt.Kopiere nachfolgenden Code in ein leeres Formmodul (Form1.vb).
' / / / Beginn Code Form1.vb
Imports System.Threading
Public Class Form1
Private WithEvents tbIn As TextBox
Private WithEvents lblOut As Label
Private mTH As Thread
Private mUnloadFlag As BooleanPrivate Delegate Sub DShowText _
(ByVal C As Control, _
ByVal Text As String)Private Sub Form1_Load _
(ByVal sender As System.Object, _
ByVal e As System.EventArgs _
) Handles MyBase.LoadCreateControls()
End SubPrivate Sub Form1_Shown _
(ByVal sender As Object, _
ByVal e As System.EventArgs _
) Handles Me.Shown' zweiten Thread starten
mTH = New Thread(AddressOf ThreadProc)
mTH.Priority = ThreadPriority.BelowNormal
mTH.Start()
End SubPrivate Sub Form1_FormClosing _
(ByVal sender As Object, _
ByVal e As FormClosingEventArgs _
) Handles Me.FormClosing' fallse der zweite Thread noch aktiv ist, ...
If mTH.IsAlive Then
mUnloadFlag = True' ... warten bis zweiter Thread beendet ist
Console.WriteLine "Warten ..."
mTH.Join()
Console.WriteLine "... und weiter gehts."
End If
End SubPrivate Sub CreateControls()
tbIn = New TextBox
With tbIn
.Name = "tbIn"
.Font = New Font("Arial", 12)
.Text = "bitte Text eingeben".SetBounds _
(10, 10, _
Me.ClientSize.Width - 20, _
.Height).Anchor = _
AnchorStyles.Left Or _
AnchorStyles.Top Or _
AnchorStyles.RightEnd With
Me.Controls.Add(tbIn)lblOut = New Label
With lblOut
.Name = "lblOut"
.Font = tbIn.Font
.AutoSize = True.Location = _
New Point(10, tbIn.Bottom + 20).Text = "....."
End With
Me.Controls.Add(lblOut)
End SubPrivate Sub ShowText _
(ByVal C As Control, _
ByVal Text As String)If C.InvokeRequired Then
' Aufruf erfolgte aus fremdem Thread
Dim D As New DShowText(AddressOf ShowText)Dim PArray() As Object = _
New Object() {lblOut, Text}' Sub ShowText erneut über den
' Delegaten DShowText aufrufen
C.Invoke(D, PArray)
Else
' Aufruf erfolgte aus dem Hauptthread
C.Text = Text
End If
End SubPrivate Sub ThreadProc()
' Diese Prozedur wird in einem zweiten Thread
' ausgeführt solange mUnloadFlag = False ist.
' Sub verlassen, wenn mUnloadFlag auf True
' gesetzt ist.Do While Not mUnloadFlag
ShowText(lblOut, Now.ToLongTimeString)
Thread.Sleep(3000)
Loop
End SubPrivate Sub tbIn_TextChanged _
(ByVal sender As Object, _
ByVal e As System.EventArgs _
) Handles tbIn.TextChangedIf lblOut IsNot Nothing Then
ShowText(lblOut, tbIn.Text)
End If
End SubEnd Class
' \ \ \ E N T ENach dem Programmstart siehst Du die Form mit einer
Textbox und einem darunter angeordneten Label.Nach dem Programmstart wird auch gleich ein zweiter
Thread (mTH) gestartet, der alle 3 Sekunden die akt.
Uhrzeit in das Label schreibt.Wenn Du Text in die Textbox eingibst, wird dieser
direkt im Label angezeigt. Dieser Zugriff auf das
Label-Steuerelement (lblOut) erfolgt aus dem Hauptthread
und kann somit direkt ohne Umweg erfolgen.Der Zugriff des zweiten Threads auf das Label-Steuerelement
zum Anzeigen der Uhrzeit kann, weil threadübergreifender
Zugriff, nicht direkt erfolgen sondern muss in der Sub ShowText
im Abfragezweigif C.InvokeRequired then
mit dem Hauptthread synchronisiert werden. Dies geschieht
indem die Sub ShowText einfach über den Delegaten
DShowText erneut aufgerufen wird.Wird die Form entladen, um das Programm zu beenden,
wird in Form_Closing geprüft, ob der zweite Thread noch am
Leben ist (mTH.IsAlive = True) und falls ja, muss diesem
zweiten Thread mitgeteilt werden, dass er sich beenden
soll (mUnloadFlag = True) und solange gewartet
werden (mTH.Join), bis dieser zweite Thread tatsächlich
beendet ist Nachdem dies geschehen ist, wird die Forrm
tatsächlich entladen und das Programm damit beendet.Gruß aus St.Georgen
Peter Götz
www.gssg.de (mit VB-Tipps u. Beispielprogrammen)- Als Antwort markiert Robert Breitenhofer Dienstag, 18. Januar 2011 11:10
Alle Antworten
-
Im Ereignis-Handler werden dann die Daten in den Textboxen dargestellt und das Datagridview aktualisiert.
Hallo Nico,
Du hast viele Fragen. Nur dazu: in einer Datareceived Event Routine darfst Du nicht direkt auf ein GUI Element der Form zugreifen. Diese Routine wird in einen sekundären thread angehoben. Dieses ist so direkt nicht erkennbar. Hier ein Codeausschnitt von mir, wie man damit umgeht. Die Empfangsdaten müssen zunächst in einen privat deklarierten buffer der Form geschrieben werden. Von dort kannst Du sie dann in ein GUI schreiben. (Hier RX_buffer.text TextBox)
zu deinen anderen Fragen: ich lese mir das noch einmal durch. Probiere erst einmal das hier.
schöne Grüße Ellen
P.S. Welches CAN Bus Interface benutzt Du?
Nachtrag: Hier die msdn Doku zu diesem Thema. Dasselbe, was ich schon gesagt habe uvm. ....
http://msdn.microsoft.com/de-de/library/system.io.ports.serialport.datareceived.aspx
' ------------------------------------------------------------------- ' write receive data to TextBox '-------------------------------------------------------------------- Public Sub DoUpdate(ByVal sender As Object, ByVal e As System.EventArgs) RxD_buffer.Text = readBuffer End Sub '--------------------------------------------------------------------- ' read COM Port '--------------------------------------------------------------------- Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, _ ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) _ Handles SerialPort1.DataReceived If comOpen Then Try ' reads string until .Newline property readBuffer = SerialPort1.ReadLine() 'data to form1 Me.Invoke(New EventHandler(AddressOf DoUpdate)) Catch ex As IO.InvalidDataException MsgBox(ex.Message) End Try End If End Sub
Ich benutze/ I'm using VB2008 & VB2010- Bearbeitet Ellen Ramcke Sonntag, 19. Dezember 2010 13:24 link zur msdn Doku
- Als Antwort markiert Robert Breitenhofer Dienstag, 18. Januar 2011 11:10
-
Uff ! Das klingt zu einfach ! Fast zu schön um wahr zu sein. Ich werde es probieren
Als CAN-Interface wird ein AT90CAN32 benutzt. Eigentlich too much; die Schaltung ist aber als Spin-off einer anderen Anwednung entstanden, die regen Gebrauch dr CAN-Mailboxen macht. Ansonsten wäre tewas anderes sicher noch einfacher.
Die Übetragung über die UART-Schnittstelle erfolgt mit einem FT232 (also USB)
-
Hallo,
Zum Thema 'threadübergeifende Zugriffe habe ich schon
einiges gelesen. Ich vermute mal, dass ich genau dieses
problem habe :-(Das Problem bekommst Du z.B. dann, wenn Du versuchst
auf eine Form oder ein Steuerelement zuzugreifen, das in
einem anderen als dem zugreifenden Thread erstellt worden
ist.
Das ist z.B. dann der Fall, wenn Deine Form u. Steuerelemente
wie meist üblich im Hauptthread erstellt worden sind und ein
weiterer (separater) Thread versucht auf die Form oder eines
der Steuerelemente zuzugreifen.Meine Postings drehen sich derzeit meist immer im ähnliche
Problemkomplexe.
Ich habe eine Schaltung, die Daten über den CAN-Bus sendet
oder empfängt und diese Daten über serielle Schnittstelle an
den PC weiterleitet - immer in Paketen zu 16 Byte.Das SerialPort-Objekt, mit dem Du vermutlich Deine Zugriffe auf
die ser. Schnittstelle realisierst arbeitet asynchron, also in einem
separaten Thread. Löst SerialPort das Ereignis _DataReceived
aus, so geschieht dies in eben diesem separaten Thread und
ein direkter Zugriff auf Deine Form oder eines der darauf befindlichen
Steuerelemente ist dann, weil threadübergreifend, nicht
zulässig und muss erst mal entsprechend mit dem Hauptthread
synchronisiert werden.Auf dem PC existiert eine Klasse in VB.NEt genannt CANBUS,
die wiederum vom COM-Port ein Ereignis bekommt wenn 16 Byte
da sind.Ich vermute mal, mit "Ereignis" meinst Du das _DataReceived-
Ereignis des SerialPorts.Dann werden die Daten ausgewertet (CRC kontrollieren, etc.) und
falls alles in Ordnung, ist unterscheidliche Events ausgelöst.
Meist ist das ein Ereignis, wenn normale Datenpakete eingetroffen
sind; es gibt aber auch Ereignisse über Fehlermeldungen u.a.
Eine einfache Testapplikation hat ein Fenster mit zahlreichen
Textboxen, in denen die Daten dargestellt werden, sowie ein Datagrid.Und an dieser Stelle bekommst Du Dein Problem mit dem
threadübergreifenden Zugriff, da der im Ereignis
SerialPort_DataReceived angestossene Code eben nicht im
Hauptthread, der auch Eigentümer Deiner Form und Controls
ist, sondern in einem eigenen (separaten) Thread läuft.Die Applikation instanziirt die Klasse CANBUS mit WithEvents
und bekommt pormpt ein Ereignis, sobald neue Dtaen angekommen
sind.
Im Ereignis-Handler werden dann die Daten in den Textboxen
dargestellt und das Datagridview aktualisiert.Der Zugriff auf diese Textboxen und das DGV darf aber nicht
direkt aus dem separaten Thread (_DataReveived) erfolgen,
sondern muss erst mit dem Hauptthread synchronisiert werden.Zu Beginn habe ich den Kopf mittels
'CheckforIllegalThreadCalls=false' aus der Schlinge gezogen.Das wäre eine recht unschöne Holzhammermethode, die Du
besser nicht anwenden solltest, weil das durchaus zu Problemen
führen kann.BeimProbieren mit einzelnen Datenpaketen in grösseren
Abständen ging das prima.
In 'real life' kommen die Daten aber recht schnell hintereinander.
Manchmal blockiert die ANwendung nach 60-100 Paketen,
manchmal läuft's aber auch lange Zeit problemlos und nur der
vertikale Balken im Datagridview hängt.Irgendwann gibt es Konflikte zwischen Hauptthread und zweitem
Thread beim Zugriffen auf Deine Form bzw. Controls.Wenn ich dann die Anweisung CheckforilllegalThreadcalls=true
setze oder rausnehme dann ist es ganz aus.Dann musst Du eben "sauber" arbeiten und Deine Zugriffe
aus dem separaten Thread "threadsicher" machen.Ich habe schon einiges zum Thema gelesen, u.a. auch auf
gssg.de und über den BackgroundWorker.Der BackgroundWorker wäre eine Möglichkeit, es geht
aber auch ohne.Hier mal ein Beispiel, das den Zugriff aus zwei verschiedenen
Threads (Hauptthread und separater Thread mTH) auf ein
Label-Steuerelement zeigt.Kopiere nachfolgenden Code in ein leeres Formmodul (Form1.vb).
' / / / Beginn Code Form1.vb
Imports System.Threading
Public Class Form1
Private WithEvents tbIn As TextBox
Private WithEvents lblOut As Label
Private mTH As Thread
Private mUnloadFlag As BooleanPrivate Delegate Sub DShowText _
(ByVal C As Control, _
ByVal Text As String)Private Sub Form1_Load _
(ByVal sender As System.Object, _
ByVal e As System.EventArgs _
) Handles MyBase.LoadCreateControls()
End SubPrivate Sub Form1_Shown _
(ByVal sender As Object, _
ByVal e As System.EventArgs _
) Handles Me.Shown' zweiten Thread starten
mTH = New Thread(AddressOf ThreadProc)
mTH.Priority = ThreadPriority.BelowNormal
mTH.Start()
End SubPrivate Sub Form1_FormClosing _
(ByVal sender As Object, _
ByVal e As FormClosingEventArgs _
) Handles Me.FormClosing' fallse der zweite Thread noch aktiv ist, ...
If mTH.IsAlive Then
mUnloadFlag = True' ... warten bis zweiter Thread beendet ist
Console.WriteLine "Warten ..."
mTH.Join()
Console.WriteLine "... und weiter gehts."
End If
End SubPrivate Sub CreateControls()
tbIn = New TextBox
With tbIn
.Name = "tbIn"
.Font = New Font("Arial", 12)
.Text = "bitte Text eingeben".SetBounds _
(10, 10, _
Me.ClientSize.Width - 20, _
.Height).Anchor = _
AnchorStyles.Left Or _
AnchorStyles.Top Or _
AnchorStyles.RightEnd With
Me.Controls.Add(tbIn)lblOut = New Label
With lblOut
.Name = "lblOut"
.Font = tbIn.Font
.AutoSize = True.Location = _
New Point(10, tbIn.Bottom + 20).Text = "....."
End With
Me.Controls.Add(lblOut)
End SubPrivate Sub ShowText _
(ByVal C As Control, _
ByVal Text As String)If C.InvokeRequired Then
' Aufruf erfolgte aus fremdem Thread
Dim D As New DShowText(AddressOf ShowText)Dim PArray() As Object = _
New Object() {lblOut, Text}' Sub ShowText erneut über den
' Delegaten DShowText aufrufen
C.Invoke(D, PArray)
Else
' Aufruf erfolgte aus dem Hauptthread
C.Text = Text
End If
End SubPrivate Sub ThreadProc()
' Diese Prozedur wird in einem zweiten Thread
' ausgeführt solange mUnloadFlag = False ist.
' Sub verlassen, wenn mUnloadFlag auf True
' gesetzt ist.Do While Not mUnloadFlag
ShowText(lblOut, Now.ToLongTimeString)
Thread.Sleep(3000)
Loop
End SubPrivate Sub tbIn_TextChanged _
(ByVal sender As Object, _
ByVal e As System.EventArgs _
) Handles tbIn.TextChangedIf lblOut IsNot Nothing Then
ShowText(lblOut, tbIn.Text)
End If
End SubEnd Class
' \ \ \ E N T ENach dem Programmstart siehst Du die Form mit einer
Textbox und einem darunter angeordneten Label.Nach dem Programmstart wird auch gleich ein zweiter
Thread (mTH) gestartet, der alle 3 Sekunden die akt.
Uhrzeit in das Label schreibt.Wenn Du Text in die Textbox eingibst, wird dieser
direkt im Label angezeigt. Dieser Zugriff auf das
Label-Steuerelement (lblOut) erfolgt aus dem Hauptthread
und kann somit direkt ohne Umweg erfolgen.Der Zugriff des zweiten Threads auf das Label-Steuerelement
zum Anzeigen der Uhrzeit kann, weil threadübergreifender
Zugriff, nicht direkt erfolgen sondern muss in der Sub ShowText
im Abfragezweigif C.InvokeRequired then
mit dem Hauptthread synchronisiert werden. Dies geschieht
indem die Sub ShowText einfach über den Delegaten
DShowText erneut aufgerufen wird.Wird die Form entladen, um das Programm zu beenden,
wird in Form_Closing geprüft, ob der zweite Thread noch am
Leben ist (mTH.IsAlive = True) und falls ja, muss diesem
zweiten Thread mitgeteilt werden, dass er sich beenden
soll (mUnloadFlag = True) und solange gewartet
werden (mTH.Join), bis dieser zweite Thread tatsächlich
beendet ist Nachdem dies geschehen ist, wird die Forrm
tatsächlich entladen und das Programm damit beendet.Gruß aus St.Georgen
Peter Götz
www.gssg.de (mit VB-Tipps u. Beispielprogrammen)- Als Antwort markiert Robert Breitenhofer Dienstag, 18. Januar 2011 11:10
-
Private Sub Form1_FormClosing _
(ByVal sender As Object, _
ByVal e As FormClosingEventArgs _
) Handles Me.FormClosing' fallse der zweite Thread noch aktiv ist, ...
If mTH.IsAlive Then
mUnloadFlag = True' ... warten bis zweiter Thread beendet ist
Console.WriteLine "Warten ..."
mTH.Join()
Console.WriteLine "... und weiter gehts."
End If
End Sub...
Private Sub ThreadProc()
' Diese Prozedur wird in einem zweiten Thread
' ausgeführt solange mUnloadFlag = False ist.
' Sub verlassen, wenn mUnloadFlag auf True
' gesetzt ist.Do While Not mUnloadFlag
ShowText(lblOut, Now.ToLongTimeString)
Thread.Sleep(3000)
Loop
End Sub
Hallo,
Ich habe/hatte ein ähnliches Problem und der Beitrag hat mir schonmal echt weitergeholfen. Danke.
Eine Zusatzfrage: Gibt es eine schnellere Möglichkeit den zweiten Thread sauber zu beenden, wenn die Form geschlossen wird?
Im zweiten Thread habe ich auch en Sleep und so wartet das Programm in diesem Fall drei Sekunden bis es schliesst, was etwas unschön ist.Es spielt mir keine Rolle, ob der Thread die Schleife noch fertig macht.
Spricht etwas dagegen das so zu machen:
Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As FormClosingEventArgs) Handles Me.FormClosing If t.IsAlive Then t.Abort() End If end sub
Gruss
Martin
-
Hallo Martin,
ein Abort sollte man vermeiden, denn das ist vergleichbar mit dem Ziehen der Handbremse
auf der Autobahn - und man weiss nicht, was dabei alles kaputt geht ;-)Besser Du verwendest einen Thread aus dem Thread-Pool via QueueUserItem.
Die sind per defintionem als Hintergrund-Thread definiert und beenden sich selbsttätig.
Oder eine BackgroundWorker-Komponente (die nutzt den ThreadPool indirekt)
und bietet zugleich die Möglichkeit, Rückmeldungen an Dein Programm zu machen.Beim BackgroundWorker wiederum kannst Du über CancelAsync, Deinen Code zum sauberen
Beenden auffordern. Der sollte dazu CancellationPending regelmässig prüfen.Ein Sleep in einem Hintergrundthread sollte man vermeiden.
Beende lieber den alten und starte ggf. eher einen neuen
(bei den oben beschrieben Verfahren ist das wenig aufwändig).Gruß Elmar
P. S.: Bitte eröffne in Zukunft einen neuen Thread und beziehe ggf. auf ältere,
das erhöht die Übersichtlichkeit.- Bearbeitet Elmar Boye Freitag, 20. Mai 2011 12:12 Sleep hinweis