Tipp-Upload: VB.NET 0278: Threading
von Spatzenkanonier
Über den Tipp
Dieser Tippvorschlag ist noch unbewertet.
Der Vorschlag ist in den folgenden Kategorien zu finden:
- Sprachmerkmale
Dem Tippvorschlag wurden folgende Schlüsselwörter zugeordnet:
thread,asynchron,gui,einfrieren,invoke,begininvoke
Der Vorschlag wurde erstellt am: 12.06.2008 20:41.
Die letzte Aktualisierung erfolgte am 30.11.2008 15:37.
Beschreibung
Zeitaufwändige Verarbeitungen führen zum "Einfrieren" der Anwendung. Denn während der Abarbeitung kann die Benutzeroberfläche (= GUI: Graphic User Interface) nicht auf Eingaben reagieren.
Abhilfe schafft man, indem man den "Job" zunächst isoliert, und dann in einen Nebenthread verlegt.
Anders als ein prozeduraler Aufruf kann ein parallel laufender Job kein Ergebnis zurückliefern (denn dann müsste gewartet werden, bis er fertig ist (=blockieren)).
Daher muß ein Job ggfs. sein Ergebnis durch Aufruf einer zusätzlichen Methode (oder durch Feuern eines Ereignisses) wieder in den Hauptthread einbringen.
Dieses Ergebnis-Einbringen muß außerdem zurückverlegt werden in den GUI-Thread, da Steuerelemente Ausnahmen werfen, wenn aus einem Nebenthread auf sie zugegriffen wird.
Die Klasse "CrossThread" bietet für die Verlegung eines Methoden-Aufrufes in einen Nebenthread die Methode "RunAsync" in 4 facher Überladung, um für bis zu 3 Argumente gewappnet zu sein. Desgleichen die Methode "RunGui" für die Rückverlagerung in den Gui-Thread.
Schwierigkeitsgrad |
Verwendete API-Aufrufe: |
Download: |
' Dieser Source stammt von http://www.activevb.de ' und kann frei verwendet werden. Für eventuelle Schäden ' wird nicht gehaftet. ' Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum. ' Ansonsten viel Spaß und Erfolg mit diesem Source! ' ' Beachten Sie, das vom Designer generierter Code hier ausgeblendet wird. ' In den Zip-Dateien ist er jedoch zu finden. ' --------- Anfang Projektgruppe SimpleThreading.sln --------- ' -------- Anfang Projektdatei SimpleThreading.vbproj -------- ' --------------- Anfang Datei CrossThread.vb --------------- ' IDE-Voreinstellungen: ' Option Explicit On ' Option Strict On ' "My Project"-Einstellungen: ' Imports Microsoft.VisualBasic.ControlChars ' Imports System.Windows.Forms ' Imports System #Region " VB2008 hat diese 3 generischen Delegaten bereits deklariert, daher sollten sie " & _ "bei Verwendung von VB2008 nicht noch einmal deklariert werden." Public Delegate Sub Action() Public Delegate Sub Action(Of T1, T2)(ByVal Arg1 As T1, ByVal Arg2 As T2) Public Delegate Sub Action(Of T1, T2, T3)(ByVal Arg1 As T1, ByVal Arg2 As T2, ByVal Arg3 As T3) #End Region ''' <summary> ''' Stellt Methoden bereit, mit denen ein beliebiger Methoden-Aufruf mit bis zu 3 Argumenten ''' in einen Nebenthread verlegt werden kann, bzw. aus einem Nebenthread in den Hauptthread ''' </summary> Public Class CrossThread Public Shared Sub RunAsync(Of T1, T2, T3)(ByVal Action As Action(Of T1, T2, T3), ByVal _ Arg1 As T1, ByVal Arg2 As T2, ByVal Arg3 As T3) ' Aufruf von Action.EndInvoke() gewährleisten, indem er als Callback-Argument ' mitgegeben wird Action.BeginInvoke(Arg1, Arg2, Arg3, AddressOf Action.EndInvoke, Nothing) End Sub Public Shared Sub RunAsync(Of T1, T2)(ByVal Action As Action(Of T1, T2), ByVal Arg1 As _ T1, ByVal Arg2 As T2) Action.BeginInvoke(Arg1, Arg2, AddressOf Action.EndInvoke, Nothing) End Sub Public Shared Sub RunAsync(Of T1)(ByVal Action As Action(Of T1), ByVal Arg1 As T1) Action.BeginInvoke(Arg1, AddressOf Action.EndInvoke, Nothing) End Sub Public Shared Sub RunAsync(ByVal Action As Action) Action.BeginInvoke(AddressOf Action.EndInvoke, Nothing) End Sub Private Shared Function GuiCrossInvoke(ByVal Action As [Delegate], ByVal ParamArray Args( _ ) As Object) As Boolean If Application.OpenForms.Count = 0 Then ' wenn kein Form mehr da ist, so tun, als ob das Invoking ausgeführt wäre Return True End If If Application.OpenForms(0).InvokeRequired Then Application.OpenForms(0).BeginInvoke(Action, Args) Return True End If End Function Public Shared Sub RunGui(Of T1, T2, T3)(ByVal Action As Action(Of T1, T2, T3), ByVal Arg1 _ As T1, ByVal Arg2 As T2, ByVal Arg3 As T3) ' falls Invoking nicht erforderlich, die Action direkt ausführen If Not GuiCrossInvoke(Action, Arg1, Arg2, Arg3) Then Action(Arg1, Arg2, Arg3) End Sub Public Shared Sub RunGui(Of T1, T2)(ByVal Action As Action(Of T1, T2), ByVal Arg1 As T1, _ ByVal Arg2 As T2) If Not GuiCrossInvoke(Action, Arg1, Arg2) Then Action(Arg1, Arg2) End Sub Public Shared Sub RunGui(Of T1)(ByVal Action As Action(Of T1), ByVal Arg1 As T1) If Not GuiCrossInvoke(Action, Arg1) Then Action(Arg1) End Sub Public Shared Sub RunGui(ByVal Action As Action) If Not GuiCrossInvoke(Action) Then Action() End Sub End Class ' ---------------- Ende Datei CrossThread.vb ---------------- ' ------------ Anfang Datei frmSimpleThreading.vb ------------ Imports System.Threading Public Class frmSimpleThreading Private Function GetFibonacci(ByVal n As Long) As Long ' die Fibonacci-Zahl wird für irgendwas in der Statistik gebraucht, k.A. ' CPU-Stresser, da pro Rekursion 2 rekursive Aufrufe. Bei z.B. n=20 ergeben sich ca. ' 2^18 Aufrufe If n < 3 Then Return 1 Return GetFibonacci(n - 1) + GetFibonacci(n - 2) End Function Private Sub Run1Second(ByVal FiboInput As Integer, ByVal IsAsync As Boolean) Dim Timeout As Date = Now + TimeSpan.FromSeconds(1) Dim Result As Long = GetFibonacci(FiboInput) Dim Counter As Long = 1L Do ' wiederholt GetFibonacci() so lange, bis 1 Sekunde herum ist. GetFibonacci(FiboInput) Counter += 1 Loop Until Now > Timeout If IsAsync Then CrossThread.RunGui(AddressOf DisplayResult, FiboInput, Result, Counter) Else DisplayResult(FiboInput, Result, Counter) End If End Sub Private Sub DisplayResult(ByVal FiboInput As Integer, ByVal Result As Long, ByVal Counter _ As Long) Me.lbFiboResult.Text = String.Concat("Fibonacci (", FiboInput, ") = ", Result, Lf, _ Counter, " times calculated") End Sub Private Sub Button_Click(ByVal sender As Object, ByVal e As EventArgs) _ Handles btBlockGUI.Click, btAsync.Click Me.lbFiboResult.Text = "" lbFiboResult.Refresh() Dim FiboInput As Integer = CInt(updFiboInput.Value) Select Case True Case sender Is btBlockGUI ' normaler Aufruf (Gui-Blockade) Run1Second(FiboInput, False) Case sender Is btAsync ' derselbe Aufruf, aber asynchron CrossThread.RunAsync(AddressOf Run1Second, FiboInput, True) End Select End Sub End Class ' ------------- Ende Datei frmSimpleThreading.vb ------------- ' --------- Ende Projektdatei SimpleThreading.vbproj --------- ' ---------- Ende Projektgruppe SimpleThreading.sln ----------
Diskussion
Diese Funktion ermöglicht es, Fragen, die die Veröffentlichung des Tipps betreffen, zu klären, oder Anregungen und Verbesserungsvorschläge einzubringen. Nach der Veröffentlichung des Tipps werden diese Beiträge nicht weiter verlinkt. Allgemeine Fragen zum Inhalt sollten daher hier nicht geklärt werden.
Um eine Diskussion eröffnen zu können, müssen sie angemeldet sein.