Threadaufruf einer Sub mit und mit ohne Parameter

    • VB.NET
    • .NET 4.0

    Es gibt 12 Antworten in diesem Thema. Der letzte Beitrag () ist von Radinator.

      Threadaufruf einer Sub mit und mit ohne Parameter

      Tach Leute!

      Ich will euch heute folgendes zeigen: Wie erstelle ich einen Thread für eine Sub, die Parameter aufnimmt - oder auch nicht.

      Als als erstes fangen wir einmal mit dem wichtigesten an: Der aufzurufenden Sub:
      (Erst einmal OHNE Parameter)

      VB.NET-Quellcode

      1. Public Sub DoSomething()
      2. '[...]
      3. End Sub

      C#-Quellcode

      1. public void DoSomething(){
      2. //[...]
      3. }


      Um jetzt eine Thread für diese Sub zu erstellen, erzeugen wir zuerst eine Instanz eines Threadobjekts:

      VB.NET-Quellcode

      1. Dim thread As new Threading.Thread(AddressOf DoSomething)

      C#-Quellcode

      1. Threading.Thread thread = new Threading.Thread(DoSomething);


      Dann "schalten" wir den Thread auf Background-Modus(d.h. wenn der Hauptthread beendet wird, der des Forms, dann wird auch der erzeugte Thread abgebrochen):

      VB.NET-Quellcode

      1. thread.IsBackground = True

      C#-Quellcode

      1. thread.IsBackground = true;


      Anschließend starten wir den Thread:

      VB.NET-Quellcode

      1. thread.Start()

      C#-Quellcode

      1. thread.Start();


      So das war ja noch der einfache Teil, jetz aber gehts an Eingemachte, denn nun wollen wir einen Thread für eine Sub mit Parameter erstellen. Dazu brauchen wir einen Delegaten: ParameterizedThreadStart:

      VB.NET-Quellcode

      1. Dim pts As New ParameterizedThreadStart(AddressOf DoSomething2)

      C#-Quellcode

      1. Threading.ParameterizedThreadStart pts = new Threading.ParameterizedThreadStart(DoSomething2);


      Und natürlich auch die Sub, die Parameter emfängt:

      VB.NET-Quellcode

      1. Public Sub DoSomething2(obj As Object)
      2. '[...]
      3. End Sub

      C#-Quellcode

      1. public void DoSomething2(object obj){
      2. //[...]
      3. }


      Dann erzeugen wir ein neues Threadobject, bei dem der Konstruktor den Delegaten empfängt, setzen ihn wieder in den Hintergrund und starten ihn mit Argumenten:

      VB.NET-Quellcode

      1. Dim thread As New Thread(pts)
      2. thread.IsBackground = True
      3. thread.Start(New Object)

      C#-Quellcode

      1. Threading.Thread thread = new Thread(pts);
      2. thread.IsBackground = true;
      3. thread.Start(new Object);



      Erklärungen:
      1.) Für den parametrisierten Start eines Threads, kann bei Option Strict On, keine einfaches New Thread(AddressOf DoSomething2() gemacht werden, denn die Signatur des Delegaten ThreadStart() stimmt nicht mit DoSomething(obj As Object) übereinstimmt.
      =>Das hat 2 Konsequenzen:
      a.)Muss eben ein Delegat verwendet werden, der eine ensprechende Signatur hat(ParameterizedThreadStart(obj As Object))
      b.)Man kann auch den unparametrisierten Start mithilfe eines Delegaten, der zur Signatur von DoSomething() passt, verwenden:

      VB.NET-Quellcode

      1. Dim ts As New ThreadStart(AddressOf DoSomething)
      2. Dim thread As New Thread(ts)
      3. thread.IsBackground = True
      4. thread.Start()

      C#-Quellcode

      1. Threading.ThreadStart ts = new Threading.ThreadStart(DoSomething);
      2. Threading.Thread thread = new Threading.Thread(ts);
      3. thread.IsBackground = true;
      4. thread.Start();

      c.)Wenn ein Thread für eine Sub mit mehrern Argumenten erstellt wird, hat man 2 Optionen das ganze zu lösen: ENTWEDER man packt zuerst die Argumente zu einem Object-Array zusammen, übergibt sie und "entpackt" sie dann in der Sub ODER man verwendet den Delegaten Action, der bis zu 16 Parameter verwenden kann(Beispiel von @ErfinderDesRades)

      Zusammengefasst:

      VB.NET-Quellcode

      1. Public Sub DoSomething1()
      2. End Sub
      3. Public Sub DoSomething2(obj As Object)
      4. End Sub
      5. Sub GenerateThread()
      6. Dim thread1 As New Thread(AddressOf DoSomething1)
      7. thread1.IsBackground = True
      8. thread1.Start()
      9. Dim pts2 As New ParameterizedThreadStart(AddressOf DoSomething2)
      10. Dim thread2 As New Thread(pts2)
      11. thread2.IsBackground = True
      12. thread2.Start(New Object)
      13. 'Alternativ den Parameterlosen Thread mit Delegaten:
      14. Dim ts3 As New ThreadStart(AddressOf DoSomething1)
      15. Dim thread3 As New Thread(ts3)
      16. thread3.IsBackground = True
      17. thread3.Start()
      18. End Sub

      C#-Quellcode

      1. public void GenerateThread()
      2. {
      3. Thread thread1 = new Thread(DoSomething1);
      4. thread1.IsBackground = true;
      5. thread1.Start();
      6. ParameterizedThreadStart pts = new ParameterizedThreadStart(DoSomething2)
      7. Thread thread2 = new Thread(pts);
      8. thread2.IsBackground = true;
      9. thread2.Start(new object);
      10. //Alternativ den Parameterlosen Thread mit Delegaten:
      11. ThreadStart ts = new ThreadStart(DoSomething1);
      12. Thread thread3 = new Thread(ts);
      13. thread3.IsBackground = true;
      14. thread3.Start();
      15. }
      16. private void DoSomething2(object time)
      17. {
      18. }
      19. private void DoSomething1()
      20. {
      21. }


      Ich hoffe ich konnte einigen helfen!

      Mfg Euer Radinator :D

      EDIT: Danke and Euch!
      In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell

      Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Radinator“ ()

      Das geht leider nur entweder ohne Argument oder mit genau einem Argument As Object.

      Meist will man aber doch intelligentere Methoden aufrufen, also welche mit mehreren Argumenten, und vor allem mit typisierten Argumenten, also was anneres als Object.

      Wie würdest du etwa eine Methode mit folgender Signatur im Nebenthread ausführen?

      VB.NET-Quellcode

      1. Private Sub AddData(position As Point, text As String)

      Als Object Array würde ich das machen

      VB.NET-Quellcode

      1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
      2. Dim StringArg As String = "Hallo Welt"
      3. Dim IntArg As Integer = 15
      4. Dim Objects As Object() = {StringArg, IntArg}
      5. Dim Thread As New Threading.Thread(New Threading.ParameterizedThreadStart(AddressOf ThreadSub))
      6. Thread.IsBackground = True
      7. Thread.Start(Objects)
      8. End Sub
      9. Private Sub ThreadSub(args As Object)
      10. Dim Objects As Object() = DirectCast(args, Object())
      11. Dim StringArg As String = DirectCast(Objects(0), String)
      12. Dim IntArg As Integer = DirectCast(Objects(1), Integer)
      13. MessageBox.Show(StringArg + IntArg.ToString())
      14. End Sub


      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Andy16823“ ()

      Wo wird da eine Methode mit der angegebenen Signatur aufgerufen?
      Nochmal die Signatur:

      VB.NET-Quellcode

      1. Private Sub AddData(ByVal position As Point, ByVal text As String)


      Edit: Meine Lösung sähe so aus:

      VB.NET-Quellcode

      1. Private Sub AddData(position As Point, text As String)
      2. 'position und text verarbeiten
      3. End Sub
      4. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
      5. Dim dlgAddData = New Action(Of Point, String)(AddressOf AddData)
      6. Dim position = Me.Location, txt = "Hallo Welt"
      7. dlgAddData.BeginInvoke(position, txt, AddressOf dlgAddData.EndInvoke, Nothing)
      8. End Sub
      Das nimmt einen Thread aus dem Threadpool.
      Allerdings wird hier nicht explizit Thread.IsBackGround gesetzt, ich weiß aber auch nicht, ob und welche Auswirkungen das hat.
      Ich verwende für solche Sachen immer eine einfache Hilfsdatenklasse.
      zB.:

      VB.NET-Quellcode

      1. ' Klasse
      2. Public Class TestClass
      3. Public Property A As String
      4. Public Property B As Integer
      5. Public Property C As Double
      6. Public Sub Perform()
      7. '....
      8. End Sub
      9. End Class
      10. ' Aufruf
      11. Dim c As New TestClass() With {.A = "Teststring", .B = 12, .C = 12.5}
      12. Dim t As New Threading.Thread(AddressOf c.Perform)
      13. t.IsBackground = True
      14. t.Start()


      lg

      EDIT:
      @ErfinderDesRades
      IsBackground bewirkt, wenn auf true, dass nach Beenden des Hauptthreads auch der erstelle Thread beendet wird.
      Bei false lauft der andere Nebenthread weiter obwohl die Hauptanwendung bereits beendet ist (bin mit nicht sicher ob die Hauptanwendung dann aktiv bleibt).

      lg
      ScheduleLib 0.0.1.0
      Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten
      Wenn ich zwischendurch mal eine Frage einwerfen dürfte: Was ist eigentlich mit dieser Schreibweise ?

      VB.NET-Quellcode

      1. Private ts As Threading.Thread
      2. ts = New Threading.Thread(Sub() draw(19, 20))
      3. ts.Start()
      4. Private Sub draw(x As Integer, y As Integer)
      5. End Sub
      @fichz: Und was passiert, wenn der BackgroundThread mit-beendet wird?
      Fliegt dort dann eine Exception? (und wäre das wünschenswert?)

      @Mojo: Auch hübsch - solch nennt man eine Closure.
      Das kann sich manchmal unerwartet verhalten, wenn Referenz-Typ-Klassenvariablen übergeben werden. In dem Fall (dann isses nämlich keine Closure mehr) muss man beachten, dass die KlassenVars nicht in der Zwischenzeit bis zur Ausführung im NebenThread sich verändern oder gar ungültig werden.
      Wie würdest du etwa eine Methode mit folgender Signatur im Nebenthread ausführen?

      VB.NET-Quellcode

      1. Private Sub AddData(position As Point, text As String)



      Also ich hab ehrlich gesagt keine Ahnung wie ich das mit mehreren Argumenten gemacht hätte, hatte nur das Problem mit nur 1 Argument :D
      Jedenfalls ich hab da auch mal gegooglet und bin dann auf folgenden Blogeintrag gestoßen:

      VB.NET-Quellcode

      1. '[...]
      2. 'Create a generic Objects Array
      3. Dim param_obj(4) as Object
      4. param_obj(0) = empId
      5. param_obj(1) = empName
      6. param_obj(2) = displayPanel
      7. param_obj(3) = log_output
      8. Sim thread As New Thread(AddressOf showEmpInfo);
      9. worker_thread.Start(param_obj);
      10. '[...]


      Also wie @Andy16823 es mit seinem Object-Array macht
      Aber das mit dem Action-Delegaten ist auch eine super Idee :D

      Mfg Radinator
      In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell

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

      Guck - ich hab jetzt festgestellt, dass man beim CurrentThread sogar nachträglich noch IsBackground setzen kann:

      VB.NET-Quellcode

      1. Private Sub AddData(position As Point, text As String)
      2. Thread.CurrentThread.IsBackground = False
      3. Thread.Sleep(1000)
      4. MessageBox.Show("Location: " & position.ToString & " Text: " & text)
      5. End Sub
      6. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
      7. Dim dlgAddData = New Action(Of Point, String)(AddressOf AddData)
      8. Dim position = Me.Location, txt = "Hallo Welt"
      9. dlgAddData.BeginInvoke(position, txt, AddressOf dlgAddData.EndInvoke, Nothing)
      10. Me.Close()
      11. End Sub
      Das Form schließt, bevor der Thread endet. Da der Thread aber auf IsBackground.False steht, wird die MessageBox noch ausgegeben.
      Kommentiert man hingegen zeile#2 aus, so wird die MessageBox nicht ausgegeben, was bedeutet, dass ThreadpoolThreads defaultmäßig IsBackground.True eingestellt sind.

      Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „ErfinderDesRades“ ()

      ErfinderDesRades schrieb:

      Wie würdest du etwa eine Methode mit folgender Signatur im Nebenthread ausführen?<br>VB.NET-Quellcode<br><br>&nbsp; &nbsp; Private Sub AddData(position As Point, text As String)



      VB.NET-Quellcode

      1. Public Class List(Of T1, T2, T3)
      2. Public Property Items As List(Of Object())
      3. Public Sub Add(item1 As T1, item2 As T2, item3 As T3)
      4. Items.Add(New Object() {item1, item2, item3})
      5. End Sub
      6. End Class


      Deswegen hab ich hier wengen der List(Of T1, T2, T3) gefragt. Jetz muss ich mir Object-Array (Object()()) machen, sondern kann einfach die List(Of T1, T2, T3) übergeben, die intern ein ObjectArry verwaltet. Wenn ich jetzt noch einen Wert ändern will, dann kann ich das bequem über die Property Items

      VB.NET-Quellcode

      1. Dim para As new Lsit(Of String, Date, Integer)
      2. para.Add("Name", CDate(01.01.2014"), 1)
      3. para.Items(0)(2) = 16 '=16


      Msg Radinator
      In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell

      Radinator schrieb:

      Deswegen hab ich hier wengen der List(Of T1, T2, T3) gefragt. Jetz muss ich mir Object-Array (Object()()) machen, sondern kann einfach die List(Of T1, T2, T3) übergeben




      Hast du Option Strict On ?

      Ich schreib nur noch mit Option Strict On, hab mir in den Settings von VS Options Explicit, Option Strict und Option Compare alle auf On gestellt.
      Warum?
      In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell