Ereignisse asynchron auslösen

8

Ich untersuche Optionen für die asynchrone Ereignisverteilung in einer Komponente, die viele Teilnehmer für ihre Ereignisse hat. Beim Durchlesen der Optionen bin ich auf dieses Beispiel gestoßen:

%Vor%

Abgesehen von der älteren Syntax (das Beispiel stammt von .NET 1.1), sieht es für mich so aus, als wäre es ein ernsthafter Ressourcenverlust. Es gibt keine Komplettierungsmethode, keine Abfrage zum Vervollständigen oder irgendeine andere Art, wie EndInvoke aufgerufen wird.

Nach meinem Verständnis muss jedes BeginInvoke ein entsprechendes EndInvoke haben . Andernfalls sind% o_de% Objektinstanzen aushängend und (möglicherweise) Ausnahmen, die während der asynchronen Ereignisse ausgelöst wurden.

Mir ist klar, dass es einfach ist, das zu ändern, indem ich einen Callback anbiete und AsyncResult mache, aber wenn ich das nicht muss. . .

Die Behandlung der asynchronen Ausnahmen ist eine ganz andere Sache, und kombiniert mit der Notwendigkeit, mit dem UI-Thread zu synchronisieren (d. h. EndInvoke usw.) könnte die ganze Idee, diese asynchronen Benachrichtigungen auszuführen, sehr gut sein.

Also, zwei Fragen:

  1. Stimmt es, dass jeder InvokeRequired eine entsprechende BeginInvoke ?
  2. benötigt?
  3. Abgesehen von dem, was ich oben erwähnt habe, gibt es andere Probleme, asynchrone Ereignisbenachrichtigungen in Windows Forms-Anwendungen zu machen?
Jim Mischel 18.03.2009, 16:12
quelle

3 Antworten

3

Ein Aufruf von BeginInvoke() sollte mit einem EndInvoke() gepaart werden, aber wenn Sie dies nicht tun, führt dies nicht zu einem Ressourcenleck. Das IAsyncResult , das von BeginInvoke() zurückgegeben wird, wird als Garbage Collection bezeichnet.

Der größte Fehler in diesem Code besteht darin, dass Sie in hohem Maße Ausnahmen ausgesetzt sind, die die Anwendung beenden. Vielleicht möchten Sie den Delegataufruf in einen Ausnahmebehandler umbrechen und sich Gedanken darüber machen, wie Sie die aufgetretenen Ausnahmen propagieren möchten (melden Sie den ersten, erstellen Sie eine Aggregatausnahme usw.).

Durch das Aufrufen einer Löschroutine mit BeginInvoke() wird ein Thread aus der Thread-Warteschlange entfernt, um das Ereignis zu starten. Dies bedeutet, dass das Ereignis immer den Haupt-UI-Thread auslöst. Dies kann dazu führen, dass einige Event-Handler-Szenarien schwieriger zu handhaben sind (z. B. Aktualisieren der UI). Behandler müssen erkennen, dass sie SynchronizationContext.Send() oder .Post() aufrufen müssen, um mit dem primären UI-Thread zu synchronisieren. Natürlich gelten auch alle anderen Multi-Thread-Programmierfehler.

    
chuckj 18.03.2009, 17:25
quelle
1

Nachdem ich eine Weile darüber nachgedacht habe, kam ich zu dem Schluss, dass es wahrscheinlich eine schlechte Idee ist, asynchrone Ereignisse in Windows Forms-Steuerelementen durchzuführen. Windows Forms-Ereignisse sollten im Benutzeroberflächenthread ausgelöst werden. Anderenfalls eine unangemessene Belastung für die Clients zu verursachen und möglicherweise mit AsyncResult -Objekten und asynchronen Ausnahmen zu verfahren.

Es ist sauberer, die Clients ihre eigene asynchrone Verarbeitung auslösen zu lassen (mit BackgroundWorker oder einer anderen Technik) oder das Ereignis synchron zu behandeln.

Es gibt natürlich Ausnahmen. System.Timers.Timer zum Beispiel löst das Ereignis Elapsed für einen Thread-Pool-Thread aus. Aber dann kommt die erste Benachrichtigung in einem Pool-Thread. Es sieht so aus, als ob die allgemeine Regel lautet: Erhebe die Ereignisse in demselben Thread, der die erste Benachrichtigung erhalten hat. Zumindest ist das die Regel, die am besten für mich funktioniert. Auf diese Weise gibt es keine Frage zu undichten Objekten.

    
Jim Mischel 31.03.2009 23:11
quelle
0
  1. Nein. EndInvoke ist nur erforderlich, wenn ein Rückgabetyp angegeben ist. Sieh dir das an: thread . Außerdem habe ich diesen Thread gepostet, der halb verwandt ist.

    >
  2. Ich kann dir wirklich nicht helfen! :-) Entschuldigung.

Mike_G 18.03.2009 17:19
quelle

Tags und Links