none
Form bleibt hängen, Einsatz von [Delegate].BeginInvoke RRS feed

  • Frage

  • Hallo,

    beim letzten Problem wurde mir echt kompetent geholfen; ich hoffe, dass das nun wieder der Fall ist.

     

    Am besten poste ich erstmal den Code:

    Public Class Form1
      Public Delegate Sub AsyncCall()
    
    
      Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim caller As New AsyncCall(AddressOf CreateForm)
    
        caller.BeginInvoke(Nothing, Nothing)
      End Sub
    
      Sub CreateForm()
        Dim Form As New Form2
        Form.Show()
      End Sub
    End Class
    
    

    Also, hierbei bleibt Form2 sofort hängen (Sanduhr, oder besser grüner Kreis - nutze Windows 7).

    Form1 läuft unbeeindruckt davon weiter...

     

    Ich habe mir jetzt gerade für ein bestimmtes Projekt ziemlich viel über das Thema Threading und asynchrone Aufrufe durchgelesen, aber das kann ich mir trotzdem nichrt erklären.

     

    Freue mich auf eure Antworten

    Danke

     

     

    Freitag, 10. September 2010 19:01

Alle Antworten

  •     Dim caller As New AsyncCall(AddressOf CreateForm)
        caller.BeginInvoke(Nothing, Nothing)

      Sub CreateForm()
        Dim Form As New Form2
        Form.Show()
      End Sub
    End Class

    Hallo M

    ich denke du vermischt zwei unterschiedliche Konzepte, wohl weil beide den Namen 'BeginInvoke' für die Methode nutzen.

    Einerseits ist der Kontext das GUI (zB Control)
    Threadsicheres Aufrufen von Windows Forms-Steuerelementen
    http://msdn.microsoft.com/de-de/library/ms171728.aspx
    Control.BeginInvoke
    http://msdn.microsoft.com/de-de/library/0b1bf3y3.aspx

    Andererseits geht es um asynchrone Ausführung (via Delegate):
    Asynchrones Aufrufen von synchronen Methoden
    http://msdn.microsoft.com/de-de/library/2e08f6yc.aspx
    welche typisch über Threads aus dem Thread-Pool geht  (und eigentlich nichts mit dem GUI zu tun haben sollte).

    Aus deinem Code geht auch nicht hervor, was schlussendlich das Ziel sein soll.
      (Code macht so fast kaum Sinn)

    Freitag, 10. September 2010 19:30
  •     Dim caller As New AsyncCall(AddressOf CreateForm)
        caller.BeginInvoke(Nothing, Nothing)

      Sub CreateForm()
        Dim Form As New Form2
        Form.Show()
      End Sub
    End Class

    Hallo M

    ich denke du vermischt zwei unterschiedliche Konzepte, wohl weil beide den Namen 'BeginInvoke' für die Methode nutzen.

    Einerseits ist der Kontext das GUI (zB Control)
    Threadsicheres Aufrufen von Windows Forms-Steuerelementen
    http://msdn.microsoft.com/de-de/library/ms171728.aspx
    Control.BeginInvoke
    http://msdn.microsoft.com/de-de/library/0b1bf3y3.aspx

    Andererseits geht es um asynchrone Ausführung (via Delegate):
    Asynchrones Aufrufen von synchronen Methoden
    http://msdn.microsoft.com/de-de/library/2e08f6yc.aspx
    welche typisch über Threads aus dem Thread-Pool geht  (und eigentlich nichts mit dem GUI zu tun haben sollte).

    Aus deinem Code geht auch nicht hervor, was schlussendlich das Ziel sein soll.
      (Code macht so fast kaum Sinn)

    Komisch, ich dachte, das wäre nicht so schwierig zu erraten, oder verletze ich irgendwelche Grundregeln:

    Es ging darum, dass sich, wenn der User auf einen Button klickt, ein (anderes) Form öffnet (und Netzwerkaufgaben in Interaktion mit dem User erfüllt).

     

    Werde beim nächsten Mal präziser sein, aber ich dachte es ist sinnvoller den Code auf ein Minimum zu reduzieren und erstmal die Eigenheiten des Threadings genauer zu verstehen.

    Um zum ursprünglichen Thema zurückzukehren:

    Es ist nicht so, dass ich die beiden Konzepte verwechselt hätte; um ehrlich zu sein kannte ich das auf GUIs bezogene Threading noch gar nicht und habe bislang den Unterschied auch noch nicht richtig verstanden. Nun ja, ich schau mir das einfach noch mal genauer an.

    Eventuell hast du 'ne kleine Erklärung parat?

     

    Freitag, 10. September 2010 20:07
  • Es ging darum, dass sich, wenn der User auf einen Button klickt, ein (anderes) Form öffnet (und Netzwerkaufgaben in Interaktion mit dem User erfüllt). 

    dieser ganze (interaktive) Vorgang gehört in den 'normalen' Ablauf (des einen GUI/App-Threads),
    es ist kein Invoke/BeginInvoke nötig/sinnvoll.

    Einzig bei deinen 'Netzwerkaufgaben' könnte es schlussendlich (punktuell) auf Prozeduren hinauslaufen, welche längere Zeit 'blockieren'  (wegen Netzwerk/Internet-Zugriff), da gibt es dann ggf Gründe für die asynchronen Ansätze (oder Threads).

    Freitag, 10. September 2010 20:27
  • Hallo,

    Aus deinem Code geht auch nicht hervor, was schlussendlich
    das Ziel sein soll. (Code macht so fast kaum Sinn)

    Komisch, ich dachte, das wäre nicht so schwierig zu erraten,
    oder verletze ich irgendwelche Grundregeln:

    Es ging darum, dass sich, wenn der User auf einen Button klickt,
    ein (anderes) Form öffnet (und Netzwerkaufgaben in Interaktion
    mit dem User erfüllt).

    Wie Thomas schon angemerkt hat, macht es wenig Sinn die
    Form2 in einem separaten Thread zu öffnen, das abarbeiten
    irgendwelcher Netzwerkaufgaben dagegen schon.

    Unter

        www.gssg.de -> Visual Basic -> VB.net
        -> Mulitthreading / BackgroundWorker

    findest Du einige Beispiele für das Abarbeiten bestimmter
    Aufgaben in separaten Threads.

    Gruß aus St.Georgen
    Peter Götz
    www.gssg.de (mit VB-Tipps u. Beispielprogrammen)

    Sonntag, 12. September 2010 16:19
  • Hallo Momo,

    Du "vermischt" hier sicher keine Konzepte sondern es ist klar aus Deiner Frage zu lesen, was gemeint ist - dabei können natürlich trotzdem mehrere Konzepte benutzt werden. Auch "müssen" hier nicht einzig Netzwerkwerkaufgaben am Blockieren Schuld sein.

    BeginInvoke blockiert hier, weil CreateForm auf einem anderen Thread läuft, als der MainThread ... das kannst Du folgendermaßen verifizieren:

         Thread.CurrentThread.ManagedThreadId

    ... und nun versucht wird, von einem anderen als dem MainThread auf Steuerelemente zuzugreifen, bzw. sie zu erstellen. Mache das über den MainThread! Also, das "Show" am besten im Haupt-Thread ausführen und eben nur eine Methode daraus in einem anderen Thread ausführen, die dann aber nicht Steuerelemente direkt modifiziert! Jedes Modifizieren von Steuerelementen benötigt den MainThread und muss ggf. "warten" oder kann ggf. blockieren!

    [->weitere Hilfen und Dokumentation dazu]
    Hier typische Verfahren, um die Responsefähigkeit bzgl. zu erhalten:

    [Bearbeiten von Steuerelementen aus Threads]
    http://dzaebel.net/ControlInvoke.htm


    ciao Frank
    Sonntag, 12. September 2010 17:51
  • Hallo M.,

    Form.Show() macht Deine Form2-Instanz einfach sichtbar, nichts mehr. Es erstellt nicht automatisch eine Nachrichtenbearbeitungsschleife auf dem neuen Thread. Da keine Nachrichtenschleife das Fenster auf dem sekundären Thread bedienen kann (die Hauptnachrichtenschleife befindet sich ja auf dem Hauptthread), scheint die Form2-Instanz zu "hängen". Dem kannst Du abhelfen, indem Du z.B. eine modale Nachrichtenschleife auf dem sekundären Thread beginnst, z.B.:

    Sub CreateForm()
     Dim Form As New Form2
     Form.ShowDialog()
    End Sub
    

    oder (nur zur Verdeutlichung):

    Sub CreateForm()
     Dim Form As New Form2
     Form.Show()
    
     While (Form.Visible)
      Application.DoEvents()
     End While
    End Sub
    
    

    oder:

    Sub CreateForm()
     Dim Form As New Form2
     Application.Run(Form)
    End Sub
    
    

    Es gibt noch weitere Spielarten, aber, wie Peter hier bereits anmerkte, macht es wenig Sinn, die Form auf einem separaten Thread auszuführen. Mein Rat deshalb: Wenn's irgendwie geht, belasse lieber die UI auf dem Hauptthread und nutze Hintergrundthreads nur für das Abarbeiten langer, evtl. blockierender Aufgaben.

    Gruß
    Marcel

    Montag, 13. September 2010 08:06
  • Hallo Marcel,

    ich bin soweit Deiner und Peters Ansicht. Bei:
        "Form.Show() macht Deine Form2-Instanz einfach sichtbar, nichts mehr."
    ist jedoch anzumerken, dass eben auch eine Neuinstanziierung der Form2 stattfindet (... ->New Form2), und insgesamt eben Steuerelemente modifiziert und erstellt werden. Das ist recht wichtig. Dazu hatte ich ja bereits durch [Bearbeiten von Steuerelementen aus Threads] Hinweise gegeben. Aber sonst ACK.


    ciao Frank
    Montag, 13. September 2010 09:32