Multithreading threadübergreifender Vorgang

  • VB.NET

Es gibt 7 Antworten in diesem Thema. Der letzte Beitrag () ist von Niko Ortner.

    Multithreading threadübergreifender Vorgang

    Hallo
    Ich beschäftige mich derzeit mit Multithreading.

    Ich habe ein test programm erstellt wo ich paralell 2 For ausführen lassen will.
    Das kannte möchte ich gerne mit multithreading realisieren.
    und den Fortschritt möchte ich gerne in ein Label sehen.


    hier mal mein gesamter code:

    VB.NET-Quellcode

    1. Public Class Form1
    2. '2 neue Threads anlegen
    3. Dim thread1 As Threading.Thread
    4. Dim thread2 As Threading.Thread
    5. 'Button1
    6. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    7. thread1 = New Threading.Thread(AddressOf schleife1)
    8. thread1.Start()
    9. End Sub
    10. 'Button2
    11. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    12. thread2 = New Threading.Thread(AddressOf schleife2)
    13. thread2.Start()
    14. End Sub
    15. 'schleife1
    16. Private Sub schleife1()
    17. For i As Integer = 0 To 1000
    18. Application.DoEvents()
    19. System.Threading.Thread.Sleep(100)
    20. Label1.Text = i.ToString
    21. Next
    22. End Sub
    23. 'schleife2
    24. Private Sub schleife2()
    25. For i As Integer = 0 To 100
    26. Label2.Text = i
    27. Application.DoEvents()
    28. System.Threading.Thread.Sleep(100)
    29. Next
    30. End Sub
    31. End Class


    Wenn ich das ganze jetzt debugge und ich zb. auf den button1 click
    bekomme ich:

    Zusätzliche Informationen: Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement Label1 erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde.

    Habe mal gelesen das man das ganze mit delegate sub und invoke irgendwie beheben kann, aber da blick ich noch nicht so durch.
    Gibt es da noch eine andere Möglichkeit das auszuführen?
    oder wenn mir das jemand mit delegate sub und invoke nähr bringt wäre ich auch sehr dankbar^^
    Gewusst wie: Threadsicheres Aufrufen von Windows Forms-Steuerelementen

    VB.NET-Quellcode

    1. Private Sub InvokeLabelTextChange(String text)
    2. If(Me.InvokeRequired)
    3. Invoke(New Action(Of String)(InvokeLabelTextChange), text)
    4. Else
    5. Label1.Text = text
    6. End If
    7. End Sub
    KaskadekingDE on GitHub :)
    Bitte keine Fragen über Programmierung per PN! Dafür ist das Forum hier.

    Who cares? ¯\_(ツ)_/¯

    Tommi8821 schrieb:

    immer noch nicht durch.
    Es ist nicht möglich, von einem Thread aus Controls, die in einem anderen Thread aus laufen, zu manipulieren. Deswegen musst Du in den Control-Thread wechseln, um dort die Veränderung vorzunehmen.
    Probier mal dies:

    VB.NET-Quellcode

    1. Private Sub schleife1()
    2. For i As Integer = 0 To 1000
    3. System.Threading.Thread.Sleep(100)
    4. Me.Invoke(Sub()
    5. Label1.Text = i.ToString
    6. Label1.Refresh()
    7. End Sub)
    8. Next
    9. End Sub
    Beachte, dass Sleep() außerhalb des Invoke()-Blocks steht.
    Und: Falls u das Programm beendest wähfrend die Threads laufen, musst Du sie beenden.
    Entweder mit Flag oder mit Holzhammer:

    VB.NET-Quellcode

    1. Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
    2. If thread1.IsAlive Then
    3. thread1.Abort()
    4. End If
    5. If thread2.IsAlive Then
    6. thread2.Abort()
    7. End If
    8. End Sub
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Moin,

    ja mit globalen Flag-Variablen, deren Wert Du dann änderst, sodass der Thread weiß, er muss aufhören und einfach die Methode verlässt.

    Grüße
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:

    Tommi8821 schrieb:

    saubere methode

    RodFromGermany schrieb:

    mit Flag
    So:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub schleife1()
    2. For i As Integer = 0 To 1000
    3. If Me.break Then
    4. Return
    5. End If
    6. System.Threading.Thread.Sleep(100)
    7. Me.Invoke(Sub()
    8. Label1.Text = i.ToString
    9. Label1.Refresh()
    10. End Sub)
    11. Next
    12. End Sub
    13. Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
    14. Me.break = True
    15. For i = 1 To 100
    16. If Not thread1.IsAlive Then
    17. Exit For
    18. End If
    19. System.Threading.Thread.Sleep(10)
    20. Next
    21. If thread1.IsAlive Then
    22. thread1.Abort()
    23. End If
    24. End Sub
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Eine potenzielle Fehlerquelle:
    Hier kann es passieren, dass das Fenster gerade geschlossen wird, Me.Invoke aber noch ausgeführt wird. Wenn dann irgendwann in der Lambda-Methode der Text des Labels verändert wird, gibt's eine ObjectDisposedException oder ähnlich. Also müsste man in der Lambda-Methode noch Me.IsDisposed prüfen.

    Eine Sache noch:
    Man kann bei Threads die IsBackground-Eigenschaft auf True setzen. Dadurch werden sie automatisch beendet, wenn die Anwendung beendet wird. Man kann, wie von RodFromGermany gezeigt, bei FormClosing noch eine Maximalzeit darauf warten, dass der Thread fertig wird, aber man spart sich das manuelle Abwürgen, wenn es zu lange dauert.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils