Thread und Delegate richtig verwendet?

  • VB.NET

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

    Thread und Delegate richtig verwendet?

    Hi,

    ich hab gemerkt, dass ich heftige Defizite in den Grundlagen hab, da ich nur aus dem Openbook für VB 2010 gelernt hab. In der 2008er Edition steht viel mehr drin seh ich grad und so bin ich bei den Delegaten.

    Ich bin gerade dabei die Delegaten zu verstehen:
    Ich verwende immer einen Delegaten, wenn ich aus einem Thread heraus eine Control ändern will, da der Delegat im Hauptthread auf die Funktion zum ändern zeigt, richtig?

    Bei den Invokes bin ich mir aber auch nicht wirklich sicher, wann muss ich jetzt Me.Invoke benutzen und wann (bspw) Label1.Invoke?

    Und noch eine Frage zu den Threads, wie kann ich ein Object-Array bei "thread1.Start" übergeben? Mir wird dann immer ein Fehler beim AddressOf countup angezeigt.

    Mal ein Test Programm:

    VB.NET-Quellcode

    1. Imports System.Threading
    2. Public Class Form1
    3. Private Delegate Sub SetTextCallback(ByVal text As String)
    4. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    5. Static thread1 As Thread
    6. If Not IsNothing(thread1) AndAlso thread1.IsAlive Then
    7. MsgBox("Thread läuft noch!")
    8. Else
    9. thread1 = New Thread(AddressOf countup)
    10. thread1.Start(20)
    11. End If
    12. End Sub
    13. Sub countup(ByVal Parameter As Object)
    14. Dim x As Integer = CInt(Parameter)
    15. For i As Integer = 0 To x
    16. Me.Invoke(New SetTextCallback(AddressOf SetText), CStr(i))
    17. Threading.Thread.Sleep(200)
    18. Next
    19. Me.Invoke(New SetTextCallback(AddressOf SetText), "Fertig")
    20. End Sub
    21. Private Sub SetText(ByVal text As String)
    22. Label1.Text = text
    23. Label1.Refresh()
    24. End Sub
    25. End Class


    Gibts an diesem Code noch was zu vereinfachen oder verbessern? Oder kann ich mir den als Muster aufbewahren?

    Danke schonmal!

    high152 schrieb:

    Ich verwende immer einen Delegaten, wenn ich aus einem Thread heraus eine Control ändern will, da der Delegat im Hauptthread auf die Funktion zum ändern zeigt, richtig?

    Ich arbeite bisher nicht viel mit Forms, aber ich kann dir sagen, dass es sicherlich nicht nur da der Fall ist.

    Mit einem Delegaten Definierst du, wie eine Methode aussehen soll, kannst sie dann für Dynamsiche Aufrufe nutzen.
    Ich habe beispiel eine Klasse gebaut, welche sich ähnlich wie List(Of ) verhält (als Übung).
    Sie kann auch sortieren.

    Sortiert wird mit einem Delegaten, sprich ich muss eine Funktion mit vorbestimmten Parametern definieren, übergebe die Funktion als Parameter (der Typ Delegate) und ich kann meiner Liste von außen sagen, wie sie sortieren muss.

    Das Invoke führt den Delegaten aus.

    Wo du einen Delegaten als Parameter stehen hast, kannst du auch dann direkt Funcs oder Subs in die Parameter-Liste schreiben (Lambdas).

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Module Module1
    2. ' Abstrakte Definition meines Delegaten (das IST mein Delegat)
    3. Public Delegate Function TestDelegate(numA As Double, numB As Double) As Double
    4. Sub Main()
    5. ' Funktionsaufruf der Funktion, welcher ein Delegat mitgegeben wird (also eine Funktion)
    6. ' New testDelegate referenziert eine neue Instanz des Delegat-Types
    7. ' AddressOf Test sagt, das die Funktion Test als Parameter mit gegeben werden soll (bzw das sich dort die zu verwendetnde Methode befindet)
    8. TestMyDelegate(412.672, 0.16283, New TestDelegate(AddressOf Test))
    9. TestMyDelegate(23, 123.312, New TestDelegate(AddressOf UmgekehrtTest))
    10. Dim delegtest As New TestDelegate(AddressOf Test)
    11. Console.WriteLine(delegtest.Invoke(123, 123))
    12. Console.ReadLine()
    13. End Sub
    14. ' Funktion, welche eine Funktion als Parameter erhält (as TestDelegate)
    15. Public Sub TestMyDelegate(num As Double, numB As Double, deleg As [Delegate])
    16. ' Aufruf der übergebenen Funktion
    17. Console.WriteLine(deleg.DynamicInvoke(num, numB))
    18. End Sub
    19. ' Funktion, welche aufgerufen wird. nicht gesondert markiert als diese
    20. Public Function Test(numA As Double, numB As Double) As Double
    21. Return numA ^ numB
    22. End Function
    23. Public Function UmgekehrtTest(numA As Double, numB As Double) As Double
    24. Return numA ^ (numB * -1)
    25. End Function
    26. End Module
    Ah sehr gut, danke für das Beispiel!
    Also könnte ich einen Delegaten beispielsweise auch "Rechenvorgang" nennen und ihn dann nach belieben durch spätes Binden die Rechenoperationen mit AddressOf zuweisen.

    Nur dann eine Frage die ich auch schon hier gelesen hab:
    Inwiefern sind Delegaten da besser?
    Ich könnte doch genauso bei anderen Umständen einfach eine andere Funktion aufrufen, die dann das Ergebnis zurückgibt, oder?

    Hat hier vielleicht jemand ein Beispiel, in dem man gut erkennen kann, wieso einmal Delegates besser sind als direkte Funktionsverknüpfungen und umgekehrt?


    Ich überleg mir die ganze Zeit welche, aber jedesmal kann ich (denke ich) das genauso ohne Delegaten lösen :S .
    Mein Verbesserungsvorschlag:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Threading
    2. Public Class Form1
    3. Private thread1 As Thread
    4. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    5. If Not IsNothing(thread1) AndAlso thread1.IsAlive Then
    6. MsgBox("Thread läuft noch!")
    7. Else
    8. thread1 = New Thread(AddressOf countup)
    9. thread1.Start(20)
    10. End If
    11. End Sub
    12. Sub countup(ByVal Parameter As Object)
    13. Dim x As Integer = CInt(Parameter)
    14. For i As Integer = 0 To x
    15. Me.Invoke(New SetTextCallback(AddressOf SetText), CStr(i))
    16. Threading.Thread.Sleep(200)
    17. Next
    18. Me.Invoke(Sub() Label1.Text = "Fertig")
    19. End Sub
    20. End Class
    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!
    Danke!(gute Idee mit der C&P Bremse ;D)

    VB.NET-Quellcode

    1. Me.Invoke(Sub() Label1.Text = "Fertig")

    Der Inhalt der Klammer wird hier also automatisch zum Delegaten der dann gleichzeitig noch die Prozedur beinhaltet, die das Label threadsicher ändert?


    Hätte mir noch jemand die Antworten für die 2 Fragen?
    Bei den Invokes bin ich mir aber auch nicht wirklich sicher, wann muss ich jetzt Me.Invoke benutzen und wann (bspw) Label1.Invoke?

    Und noch eine Frage zu den Threads, wie kann ich ein Object-Array bei "thread1.Start" übergeben? Mir wird dann immer ein Fehler beim AddressOf countup angezeigt.

    Kagurame schrieb:

    Du musst natürlich das Delegat invoken. Me bezieht sich auf "mich", ich bin "Die Klasse, die Instanz", und Lebl ist eben Label. Ein Laben wird wohl kaum ein Delegate sein, oder?
    Mich hat das während meiner Recherche in diesem Thread etwas irritiert:
    [VB.NET] Multithreading | Control aus dem Hintergrundthread mit Invoke und Delegates

    Edith: OK, dann immer Me.Invoke benutzen, ich merks mir.
    Wie siehts damit aus auf meinen Beispiel Code bezogen:

    Und noch eine Frage zu den Threads, wie kann ich ein Object-Array bei "thread1.Start" übergeben? Mir wird dann immer ein Fehler beim AddressOf countup angezeigt.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „high152“ ()

    high152 schrieb:

    ich hab gemerkt, dass ich heftige Defizite in den Grundlagen hab, da ich nur aus dem Openbook für VB 2010 gelernt hab. In der 2008er Edition steht viel mehr drin seh ich grad und so bin ich bei den Delegaten.

    Das VB-Openbook von Galileo ist Mist. Also wenn du Defizite eher vermeiden möchtest, dann folge dem Link.