Funktion per Thread starten.

  • VB.NET

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von FatFire.

    Funktion per Thread starten.

    Hey,


    wie kann man eine Funktion über einen Thread starten? Also:

    VB.NET-Quellcode

    1. Private Function Test(Byval str as String)
    2. End Function


    Wie starte ich einen Thread der auf diese Funktion zugreifen soll?
    Parameter musst du beim Aufruf der Start-Methode übergeben.

    VB.NET-Quellcode

    1. Public Function Foo(ByVal Bar As String)
    2. MessageBox.Show(Bar)
    3. End Function
    4. Dim FooThread As New Threading.Thread(AddressOf Foo)
    5. FooThread.Start("Hey.")

    Und CheckForIllegalCrossThreadCalls vergisst du mal ganz schnell wieder. ;)
    (Achtung, gleich meckern alle)

    Wenn Du es weißt, warum...

    1. empfiehlst Du es dann?
    2. machst Du Dich nicht schlau warum alle meckern?
    3. benutzt Du es, obwohl es den Threadersteller nicht einmal beim Problem hilft?

    Delegaten und Hilfskonstrukte wie der Backgroundworker wurden ja nicht aus Jux und Dollerei implementiert.

    @AsdAsd1337: CheckForIllegalCrossThreadCalls solltest Du niemals antasten. Es gibt kein Szenario in dem das Umstellen auf false einen produktiven Vorteil bringt, damit vertuschst Du nur schlampig programmierten Code.

    Wichtige Quellen unter anderem: Multithread-Programmierung mit Visual Basic, Verwaltetes Threading und VB.NET Tipps: Multithreading, wobei dort diese Stelle über Marshalling für Dich am interessantesten sein dürfte.

    Gruß FatFire
    Habs jetzt nicht probiert, aber wäre untiges nicht ne Lösung für alle "Faulpelze"?

    VB.NET-Quellcode

    1. Private Sub ControlPropSetter(ByVal ctl As Control, ByVal propname As String, ByVal value As Object)
    2. Try
    3. ctl.GetType.GetProperty(propname).SetValue(ctl, value, Nothing)
    4. Catch ex As Exception
    5. Debug.Print(ex.Message)
    6. End Try
    7. End Sub
    8. Private Delegate Sub dlgControlPropSetter(ByVal ctl As Control, ByVal propname As String, ByVal value As Object)
    9. Private Sub ThreadSafeSet(ByVal ctl As Control, ByVal propname As String, ByVal value As Object)
    10. If ctl.InvokeRequired Then
    11. Dim dlg As dlgControlPropSetter = AddressOf ControlPropSetter
    12. ctl.Invoke(dlg, New Object() {ctl, propname, value})
    13. Else
    14. ControlPropSetter(ctl, propname, value)
    15. End If
    16. End Sub

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

    @picoflop: Das.. ist genial. Nach so vielen Zeilen UI-Code hätte mir die Idee auch mal kommen können.
    Man müsste nur mal testen wie groß der Performance-Unterschied da ist, wenn man die Zuweisung über Reflection löst, oder ab wann es sich bemerkbar machen würde.
    Meintest Du nicht:

    VB.NET-Quellcode

    1. ctl.Invoke(dlg, ctl, propname, value)

    statt

    VB.NET-Quellcode

    1. dlg.Invoke(ctl, propname, value)

    ?...Huch, ach, schon korrigiert...schlimmer Finger und ich bastel hier rum :P

    Naja, obiges geht auch und Du mußt Dir kein Object-Array basteln, weil es eh als ParamArray übergeben wird.

    Gruß FatFire

    Edit: Man könnte da bestimmt noch einiges Logik dahinterpacken, damit die Performance optimiert wird...wenn Änderungen in zu schneller Folge ankommen z.B. nur jede x-te auch an das Control senden (macht beim Textbox.Text ja Sinn) oder die Änderungen sammeln und dann auf einen Schlag absetzen (z.B. AppendLines von einer RTB oder Items.Add im Rahmen eines Listbox-Updates)...ach, letztendlich ist es in den meisten Fällen halt doch nicht mit einem einfachen "sende Objekt A an Methode B getan". Aber schon ein schönes Lernstück :)

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

    FatFire schrieb:

    Edit: Man könnte da bestimmt noch einiges Logik dahinterpacken

    Evtl zwischenspeichern von control, Property etc in irgendeiner List.

    MW. frisst aber doch schon der Delegate an sich verhältnissmäßig (!) viel Performance?

    Vlt findet sich ja jemand, der das ganze "schön" macht und mal in den sourcecode-Austausch packt. Dann hat vlt dieses ewige hin- und her mit den threadübergreifenden Vorgängen ein Ende. Ein Newbie braucht dann nur noch C&P.
    Immer noch besser als die Überprüfung disablen ;)

    EDIT: Sollte vermutlich auch gesynclocked werden oder?

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

    Also, ich hab da jetzt was gebastelt...aber das dürfte...naja, irgendwie sieht es für mich sehr sonderbar aus und ich glaube performancemässig nimmt sich das jetzt gar nichts mit Deiner Methode:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Module GUIHelper
    2. Private Delegate Sub InvokeDelegateWOReturn(ByVal Control As System.Windows.Forms.Control, _
    3. ByVal Method As String, ByVal Flags As System. _
    4. Reflection.BindingFlags, ByVal Values As Object())
    5. Private Delegate Function InvokeDelegateWReturn(ByVal Control As System.Windows.Forms.Control, _
    6. ByVal Method As String, ByVal Flags As System. _
    7. Reflection.BindingFlags, ByVal Values As Object()) As Object
    8. Private SetSomethingDelegateInstance As New InvokeDelegateWOReturn(AddressOf SetSomething)
    9. Private GetSomethingDelegateInstance As New InvokeDelegateWReturn(AddressOf GetSomething)
    10. Private Sub SetSomething(ByVal Control As System.Windows.Forms.Control, ByVal Method As String, _
    11. ByVal Flags As System.Reflection.BindingFlags, ByVal Values As Object())
    12. If Control.InvokeRequired Then
    13. Control.Invoke(SetSomethingDelegateInstance, Control, Method, Flags, Values)
    14. Else
    15. Control.GetType.InvokeMember(Method, Flags, System.Type.DefaultBinder, Control, Values)
    16. End If
    17. End Sub
    18. Private Function GetSomething(ByVal Control As System.Windows.Forms.Control, ByVal Method As String, _
    19. ByVal Flags As System.Reflection.BindingFlags, ByVal Values As Object()) As Object
    20. If Control.InvokeRequired Then
    21. Return Control.Invoke(GetSomethingDelegateInstance, Control, Method, Flags, Values)
    22. Else
    23. Return Control.GetType.InvokeMember(Method, Flags, Nothing, Control, Values)
    24. End If
    25. End Function
    26. Public Sub SetProperty(ByVal Control As System.Windows.Forms.Control, ByVal Method As String, _
    27. ByVal ParamArray Values As Object())
    28. SetSomething(Control, Method, Reflection.BindingFlags.SetProperty, Values)
    29. End Sub
    30. Public Function GetProperty(ByVal Control As System.Windows.Forms.Control, ByVal Method As String, _
    31. ByVal ParamArray Values As Object()) As Object
    32. Return GetSomething(Control, Method, Reflection.BindingFlags.GetProperty, Values)
    33. End Function
    34. Public Function InvokeMethod(ByVal Control As System.Windows.Forms.Control, ByVal Method As String, _
    35. ByVal ParamArray Values As Object()) As Object
    36. Return GetSomething(Control, Method, Reflection.BindingFlags.InvokeMethod, Values)
    37. End Function
    38. Public Sub SetField(ByVal Control As System.Windows.Forms.Control, ByVal Method As String, _
    39. ByVal ParamArray Values As Object())
    40. SetSomething(Control, Method, Reflection.BindingFlags.SetField, Values)
    41. End Sub
    42. Public Function GetField(ByVal Control As System.Windows.Forms.Control, ByVal Method As String, _
    43. ByVal ParamArray Values As Object()) As Object
    44. Return GetSomething(Control, Method, Reflection.BindingFlags.GetField, Values)
    45. End Function
    46. End Module


    Das Modul kann man irgendwie in sein Projekt mit reinschleppen und z.B. so den Text einer Textbox setzen

    VB.NET-Quellcode

    1. GUIHelper.SetProperty(TextBox1, "Text", "Hier halt der Text.")

    Oder eine Methode ausführen:

    VB.NET-Quellcode

    1. GUIHelper.InvokeMethod(TextBox1, "AppendText", " Und hier noch mehr Text.")


    Ihr könnt es auch ja mal anschauen. Ganz gut finde ich es, weil Delegaten nur für die beiden Funktionen im Modul nötig sind und diese ständig deklariert bleiben können...vielleicht bringt das ja ein wenig Performance.

    Gruß FatFire

    PS: Picoflop, wäre da vor allem sehr an Deiner Meinung interessiert. Vor allen Dingen wegen Synclock (Du kennst da ja meine Schwäche :P ). Obwohl ich da eigentlich keine Notwendigkeit sehe, die Sachen im GUI-Thread müssen so oder nacheinander abgearbeitet werden und bei meiner Implementierung als statische Methoden in einem Modul dürfte es da auch keine Probleme geben, weil sowas prinzipbedingt sicher ist. Es werden ja auch keine statischen Werte mittendrin neu belegt.

    FatFire schrieb:

    Obwohl ich da eigentlich keine Notwendigkeit sehe, die Sachen im GUI-Thread müssen so oder nacheinander abgearbeitet werden

    Hatte noch die Idee evtl als optionalen Parameter "Async" mit anzugeben, so dass man entweder Invoke oder BeginInvoke arbeitet.
    ansonsten sieht der Code doch schon mal gut aus.
    Synclock ja/nein .. k.A ehrlich. Ich bau's halt im Zweifel lieber immer einmal zu viel als einmal zu wenig ein.
    Also ich hab da jetzt noch ein wenig sonderbares Verhalten, wenn ich die draufzugreifenden Threads nicht irgendwie mal kurz ausbremse mit Sleep. Scheinbar können mehrere parallel laufende Threads den GUI-Thread durchaus an die Wand drücken, dass der keine Luft mehr zum Atmen hat. Mit Synclock seh ich da auch keine Änderung oder ich hab es mal wieder falsch benutzt :D

    Gruß FatFire

    Edit: Das mit Async ist natürlich auch noch mal ne Idee...