2009-12-15 10 views
16

Grüße, Ich entwickle eine Anwendung in C#. Im Moment beschäftige ich mich mit Threading und ich habe eine Frage, die ich in meinem Kopf habe. Was ist der Unterschied zwischen Invoke und BeginInvoke? las ich etwas Faden und ich fand einige nützliche Informationen hier: hereInvoke und BeginInvoke

jedoch, was der Unterschied zwischen Invoke und BeginInvoke in dem folgenden Code ist:

private void ProcessRoutine() 
{ 
    for (int nValue = StartFrom; nValue <= EndTo; nValue++) 
    { 
     this.Invoke(this.MyDelegate, nValue); 
     //this.BeginInvoke(this.MyDelegate, nValue); 
    } 
    MessageBox.Show("Counting complete!"); 
} 
private void MessageHandler(int progress) 
{ 
    lblStatus.Text = lblStatus.Text = "Processing item: " + progress.ToString(); 
    progressBar1.Value = progress; 
} 

wo MyDelegate ein Verweis auf Messagefunktion ist.

Ich habe festgestellt, dass BeginInvoke lblStatus.Text nicht aktualisiert wird, wenn die Verwendung von Invoke das Etikett aktualisiert. Außerdem weiß ich, dass Invoke wartet, bis seine Ausführung abgeschlossen ist. Der wichtigste Fall, der mich interessiert, ist, warum es in diesem Fall einen Unterschied beim Aktualisieren von Etikettentext gibt.

Antwort

8

Mit Invoke wird die Methode ausgeführt und die Anwendung wartet darauf, dass sie ausgeführt wird.

Mit BeginInvoke wird die Methode Asychnronous aufgerufen und die Anwendung wird weiterhin ausgeführt, während die in BeginInvoke referenzierte Methode ausgeführt wird.

Mit BeginInvoke müssen Sie EndInvoke aufrufen, um die Ergebnisse der Methode zu erhalten, die Sie mit BeginIvnoke ausgeführt haben.

Sie sollten GUI-Komponenten in BeginXXX-Methoden nicht aktualisieren, da sie in einem anderen Thread im GUI-Thread ausgeführt werden, im Gegensatz zu Ihrer Invoke-Methode. Sie können nicht auf GUI-Komponenten in einem anderen Thread für den GUI-Thread zugreifen.

Hoffe, das hilft!

+12

BeginInvoke aufrufen, bedeutet nicht, es nicht auf der Benutzeroberfläche ausgeführt ist Faden. Das bedeutet, dass es asynchron für den Thread aufgerufen wird, der mit "this" verknüpft ist. Dies könnte der UI-Thread sein. –

+0

also, wenn es nicht in einem anderen Thread ist, wie funktioniert es dann? –

+8

Von MSDN: "Führt den angegebenen Delegaten asynchron für den Thread aus, auf dem das zugrunde liegende Steuerelement des Steuerelements erstellt wurde". Wenn es also vom Benutzeroberflächenthread aufgerufen wird, wird es in eine Warteschlange gestellt und ausgeführt, wenn es sich im UI-Thread im Leerlauf befindet. Was wird sein, nachdem die aktuell ausgeführte Methode zurückgegeben wurde. –

1

BeginInvoke führt den Methodenkörper in einem anderen Thread aus und ermöglicht, dass der aktuelle Thread fortgesetzt wird. Wenn Sie versuchen, eine Steuerelementeigenschaft direkt von einem anderen Thread zu aktualisieren, wird eine Ausnahme ausgelöst.

+1

ja, ich weiß, aber warum mein Label Text mit Invoke aktualisiert wird und mit BeginInvoke ist es nicht –

+0

@Niao den zweiten Satz meiner Antwort sehen –

0

Dies läuft im Grunde darauf ab, ob das Steuerelement synchron oder asynchron aktualisiert werden soll. Das hängt von Ihrer speziellen Situation ab.

18

zu beginnen, von Ihrem Link:

  • Control.Invoke: Führt auf dem UI-Thread, aber Thread wartet, bevor Sie fortfahren abgeschlossen sein Aufruf.
  • Control.BeginInvoke: Wird auf dem asynchronen UI-Thread ausgeführt, und der aufrufende Thread wartet nicht auf den Abschluss.

und von MSDN:

BeginInvoke führt die angegebenen Delegaten asynchron für den Thread, der die zugrunde liegende Handelte Kontrolle wurde auf erstellt.

Um es zusammenzufassen, BeginInvoke ist asynchron. Wenn BeginInvoke aus dem UI-Thread aufgerufen wird, wird die Anforderung parallel zum UI-Thread ausgeführt. Dies bedeutet, dass es erst ausgeführt werden kann, nachdem die aktuell ausgeführte Methode zurückgegeben wurde.In diesem Fall scheint das Textfeld nie aktualisiert zu werden, da die for-Schleife nicht unterbrochen wird, da der aufrufende Thread nicht darauf wartet, dass dieses Ereignis abgeschlossen wird, bevor es fortgesetzt wird.

Alternativ ist Invokesynchron. Das Textfeld wird aktualisiert, da der aufrufende Thread auf den Abschluss des Aufrufs wartet, bevor die Ausführung fortgesetzt wird.

+2

Ein kleiner Punkt - es wird nicht ausgeführt, wenn die Methode zurückkehrt, es ist wie ein Feuer und vergessen - es ist in den COM/winapi Ether abgefeuert –

+0

Vielen Dank für Ihr Feedback; Ich habe gerade meine Antwort aktualisiert. –

5

Control.BeginInvoke funktioniert nicht auf einem anderen Thread (oder Threadpool), ein Delegat.BeginInvoke tut. MSDN Motto sagt:

den angegebenen Delegaten Führt asynchron für den Thread, dass die zugrunde liegende Handle Kontrolle war erstellt auf.

jedoch Control.BeginInvoke verwendet einfach PostMessage und kehrt - keine CLR Thread erstellt wird.

Die Funktion Postmessage stellt (posts) eine Meldung in der Meldungswarteschlange mit dem Faden verbunden, dass erstellt das angegebene Fenster und zurückkehrt, ohne für den Thread wartet die Nachricht zu verarbeiten.

This article fasst, ob recht gut Invoke oder BeginInvoke verwenden:

Welche zu verwenden, funktionieren, fragen Sie. Es hängt wirklich von Ihrer Anforderung ab. Wenn Sie möchten, dass Ihre UI-Aktualisierung beendet, bevor Sie fortfahren, verwenden Sie Invoke. Wenn gibt es keine solche Anforderung, würde ich vorschlagen mit BeginInvoke, wie es macht den Thread ruft scheinbar "schneller". Es gibt ein paar Gotchas mit BeginInvoke.

  • Wenn die Funktion Sie über BeginInvoke rufen geteilten Zustandszugriffe (Zustand geteilt zwischen dem UI-Thread und anderen Threads), Sie sind in Schwierigkeiten. Der Zustand könnte zwischen der Zeit ändern, die Sie BeginInvoke aufgerufen haben, und wenn die umschlossene Funktion tatsächlich ausgeführt wird, was zu schwer zu Timing-Problemen zu finden.
  • Wenn Sie die Referenzparameter an die über BeginInvoke aufgerufene Funktion übergeben, müssen Sie sicherstellen, dass kein anderer das übergebene Objekt ändert, bevor die Funktion abgeschlossen wird. In der Regel Klonen das Objekt vor der Übergabe an BeginInvoke, , die das Problem insgesamt vermeidet.