Multithreading - Richtig?

  • VB.NET

Es gibt 22 Antworten in diesem Thema. Der letzte Beitrag () ist von Artentus.

    Multithreading - Richtig?

    Also,

    Ich übe gerade multithreading.

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    3. Dim Thread_LangerVorgang As System.Threading.Thread
    4. Thread_LangerVorgang = New System.Threading.Thread(AddressOf MeineSub)
    5. CheckForIllegalCrossThreadCalls = False
    6. Thread_LangerVorgang.Start()
    7. End Sub
    8. Private Sub MeineSub()
    9. Dim i As Integer
    10. For i = 1 To 10000
    11. Threading.Thread.Sleep(1)
    12. Label1.Text = CType(i, String)
    13. Next
    14. End Sub
    15. End Class


    Dieser Code funktioniert, allerdings habe ich oft gehört das CheckForIllegalCrossThreadCalls = False kein schöner programmierstil ist.
    Wie löse ich das richtig/vernünftig?
    C# Developer
    Learning C++
    Probiere es doch einfach mit

    VB.NET-Quellcode

    1. me.invoke(Sub() Label1.Text = CType(i, String))

    und lass das weg :

    VB.NET-Quellcode

    1. CheckForIllegalCrossThreadCalls = False
    MFG 0x426c61636b4e6574776f726b426974
    InOffical VB-Paradise IRC-Server
    webchat.freenode.net/
    Channel : ##vbparadise

    Artentus schrieb:

    BeginInvoke(Sub() Label1.Text = i.ToString())

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    3. Dim Thread_LangerVorgang As System.Threading.Thread
    4. Thread_LangerVorgang = New System.Threading.Thread(AddressOf MeineSub)
    5. ' CheckForIllegalCrossThreadCalls = False
    6. Thread_LangerVorgang.Start()
    7. End Sub
    8. Private Sub MeineSub()
    9. Dim i As Integer
    10. For i = 1 To 10000
    11. Threading.Thread.Sleep(1)
    12. BeginInvoke(Sub() Label1.Text = i.ToString())
    13. Next
    14. End Sub
    15. End Class


    Da erhöht sich der Counter aber iwie nicht? Was mach ich falsch? ?(

    EDIT: Geht doch, aber ich bekomme wenn ich meine Anwendung schließe und der Counter noch am laufen ist diese Exception:

    C# Developer
    Learning C++
    Ja, das ist etwas, dem du vorbeugen musst. Du solltest vor dem Schließen den Thread irgendwie dazu bringen, sich zu beenden (am einfachsten durch eine Boolean-Variable), und dann warten, bis er sich beendet hat. Erst dann kannst du das Programm (und damit die Form) schließen.
    Selber machen:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private isClosing As Boolean
    3. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    4. Dim Thread_LangerVorgang As System.Threading.Thread
    5. Thread_LangerVorgang = New System.Threading.Thread(AddressOf MeineSub)
    6. Thread_LangerVorgang.Start()
    7. End Sub
    8. Private sub Form1_Closing(sender As Object, e As EventArgs) Handles MyBase.Closing
    9. IsClosing = True
    10. End Sub
    11. Private Sub MeineSub()
    12. For i = 1 To 10000
    13. If isClosing Then Return
    14. Threading.Thread.Sleep(1)
    15. BeginInvoke(Sub() Label1.Text = i.ToString())
    16. Next
    17. End Sub
    18. End Class
    So mache ich das immer:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private isClosing As Boolean
    3. Private Thread_LangerVorgang As Thread
    4. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    5. Thread_LangerVorgang = New System.Threading.Thread(AddressOf MeineSub)
    6. Thread_LangerVorgang.Start()
    7. End Sub
    8. Private sub Form1_Closing(sender As Object, e As EventArgs) Handles MyBase.Closing
    9. isClosing = True
    10. If Thread_LangerVorgang.Join(100) = False Then
    11. Thread_LangerVorgang.Abort()
    12. End If
    13. End Sub
    14. Private Sub MeineSub()
    15. For i = 1 To 10000
    16. If isClosing Then Return
    17. Threading.Thread.Sleep(1)
    18. BeginInvoke(Sub() Label1.Text = i.ToString())
    19. Next
    20. End Sub
    21. End Class


    In deinem Fall kann noch das Problem auftreten, dass es nen Deadlock geben kann.


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    Ok, noch ne frage, wenn ich den Button nach Thread-Start disable, und ich ihn, wenn i = 1000 ist wieder enabled = true setze, dann krieg ich diesen Fehler:



    Mein Code:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private isClosing As Boolean
    3. Private Thread_LangerVorgang As Threading.Thread
    4. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    5. Thread_LangerVorgang = New System.Threading.Thread(AddressOf MeineSub)
    6. Thread_LangerVorgang.Start()
    7. Button1.Enabled = False
    8. End Sub
    9. Private Sub Form1_Closing(sender As Object, e As EventArgs) Handles MyBase.Closing
    10. isClosing = True
    11. If Thread_LangerVorgang.Join(100) = False Then
    12. Thread_LangerVorgang.Abort()
    13. End If
    14. End Sub
    15. Private Sub MeineSub()
    16. For i = 1 To 1000
    17. If isClosing Then Return
    18. Threading.Thread.Sleep(1)
    19. BeginInvoke(Sub() LabelPrg.Text = i.ToString())
    20. If i = 1000 Then
    21. Button1.Enabled = True
    22. End If
    23. Next
    24. End Sub
    25. End Class
    C# Developer
    Learning C++
    Das ist doch genau das selbe Problem, weswegen du den Thread ursprünglich aufgemacht hast, folglich ists auch die selbe Lösung.
    Auch und übrigens anstatt innerhalb der Schleife abzufragen, ob i 1000 ist, kannst du den Button auch einfach nach der Schleife wieder aktivieren.
    Wenn du Code kopierst welchen du nicht verstehst, musst du fragen.
    Was macht: BeginInvoke(Sub() LabelPrg.Text = i.ToString())?


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    @thefiloe

    Stimmt, ist ja das gleiche, also habs so gemacht:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private isClosing As Boolean
    3. Private Thread_LangerVorgang As Threading.Thread
    4. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    5. Thread_LangerVorgang = New System.Threading.Thread(AddressOf MeineSub)
    6. Thread_LangerVorgang.Start()
    7. Button1.Enabled = False
    8. End Sub
    9. Private Sub Form1_Closing(sender As Object, e As EventArgs) Handles MyBase.Closing
    10. isClosing = True
    11. If Thread_LangerVorgang.Join(100) = False Then
    12. Thread_LangerVorgang.Abort()
    13. End If
    14. End Sub
    15. Private Sub MeineSub()
    16. For i = 1 To 1000
    17. If isClosing Then Return
    18. Threading.Thread.Sleep(1)
    19. BeginInvoke(Sub() LabelPrg.Text = i.ToString())
    20. If i = 1000 Then
    21. BeginInvoke(Sub() Button1.Enabled = True)
    22. End If
    23. Next
    24. End Sub
    25. End Class
    C# Developer
    Learning C++

    Artentus schrieb:

    anstatt innerhalb der Schleife abzufragen, ob i 1000 ist, kannst du den Button auch einfach nach der Schleife wieder aktivieren.

    VB.NET-Quellcode

    1. Private Sub MeineSub()
    2. For i = 1 To 1000
    3. If isClosing Then Return
    4. Threading.Thread.Sleep(1)
    5. BeginInvoke(Sub() LabelPrg.Text = i.ToString())
    6. Next
    7. BeginInvoke(Sub() Button1.Enabled = True)
    8. End Sub
    aber dassis doch immer noch Overkill:

    VB.NET-Quellcode

    1. For i = 1 To 1000
    2. If isClosing Then Return
    3. Threading.Thread.Sleep(1)
    4. BeginInvoke(Sub() LabelPrg.Text = i.ToString())
    5. Next
    1000 mal, jede Millisekunde ein Label neu betexten - welche ArmeSau soll das Label angugge ;( ?

    Tatsächlich kommt da nichtmal der Bildschirm hinterher - also es ist reines CPU-Power verbraten.