Ist es möglich, einen event-handler auf einem anderen thread an den Aufrufer?
Können sagen, ich habe eine Komponente namens Tasking (das kann ich nicht ändern) was macht eine Methode "DoTask", die einige möglicherweise langwierigen Berechnungen und gibt das Ergebnis über eine Veranstaltung TaskCompleted. Normalerweise, das heißt in ein windows-Formular, das der Benutzer schließt nach bekommt Sie die Ergebnisse.
In meinem speziellen Szenario, das ich brauche zu assoziieren einige Daten (Datenbank-Datensatz) mit den zurückgegebenen Daten in TaskCompleted und verwenden Sie, um update-Datensatz in der Datenbank.
Hab ich untersuchte den Einsatz von AutoResetEvent zu Benachrichtigen, wenn das Ereignis behandelt wird. Das problem ist AutoResetEvent.WaitOne() blockiert und die event-handler wird nie aufgerufen. Normalerweise AutoResetEvents genannt werden, ist ein separater thread, also denke ich, das bedeutet, dass der event-handler ist auf dem gleichen thread die Methode aufruft.
Im wesentlichen, ich möchte einen asynchronen Aufruf, in dem die Ergebnisse zurückgegeben werden, über ein Ereignis, in einem synchronen Aufruf (ie call DoSyncTask aus einer anderen Klasse) blockiert bis das Ereignis behandelt wird und die Ergebnisse an einem Ort zugänglich zu beiden die event handler und die Methode, die die Methode aufgerufen, die den asynchronen Aufruf.
public class SyncTask
{
TaskCompletedEventArgs data;
AutoResetEvent taskDone;
public SyncTask()
{
taskDone = new AutoResetEvent(false);
}
public string DoSyncTask(int latitude, int longitude)
{
Task t = new Task();
t.Completed = new TaskCompletedEventHandler(TaskCompleted);
t.DoTask(latitude, longitude);
taskDone.WaitOne(); //but something more like Application.DoEvents(); in WinForms.
taskDone.Reset();
return data.Street;
}
private void TaskCompleted(object sender, TaskCompletedEventArgs e)
{
data = e;
taskDone.Set(); //or some other mechanism to signal to DoSyncTask that the work is complete.
}
}
In a Windows App the following works correctly.
public class SyncTask
{
TaskCompletedEventArgs data;
public SyncTask()
{
taskDone = new AutoResetEvent(false);
}
public string DoSyncTask(int latitude, int longitude)
{
Task t = new Task();
t.Completed = new TaskCompletedEventHandler(TaskCompleted);
t.DoTask(latitude, longitude);
while (data == null) Application.DoEvents();
return data.Street;
}
private void TaskCompleted(object sender, TaskCompletedEventArgs e)
{
data = e;
}
}
Brauche ich nur, um zu replizieren, dass das Verhalten in einem Fenster-service, wo die Anwendung.Führen Sie nicht aufgerufen und die Datei ApplicationContext Objekt ist nicht verfügbar.
- Hier ist ein gutes video zu verstehen
AutoResetEvent
youtube.com/watch?v=xaaRBh07N34
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich hatte einige Probleme in letzter Zeit mit der Herstellung asynchrone Aufrufe und Veranstaltungen an threads und Rückkehr zu den Haupt-thread.
Ich verwendet SynchronizationContext um den überblick zu behalten. Die (pseudo) - code unten zeigt, was funktioniert für mich im moment.
Ich hoffe, dies hilft, wie es behoben das problem für mich.
Vielleicht könnten Sie sich DoSyncTask zu starten, wird ein timer-Objekt, der überprüft, ob der Wert Ihrer Daten-variable an einer geeigneten Intervall. Sobald die Daten einen Wert, Sie können dann ein weiteres Ereignis, Feuer, Ihnen zu sagen, dass Daten, die jetzt einen Wert hat (und schließen, die timer off natürlich).
Ziemlich hässlicher hack, aber es könnte funktionieren... in der Theorie.
Sorry, das ist die beste, die ich kann kommen mit der Hälfte eingeschlafen. Zeit fürs Bett...
Habe ich eine Lösung für das async zu sync-problem, zumindest mit allen .NET-Klassen.
http://geekswithblogs.net/rgray/archive/2009/01/29/turning-an-asynchronous-call-into-a-synchronous-call.aspx
Es funktioniert immer noch nicht mit COM. Ich vermute, weil der STA-threading. Das Ereignis ausgelöst durch die .NET-Komponente hostet, die den COM OCX ist nie behandelt, von meiner worker-thread, so bekomme ich ein deadlock auf WaitOne().
jemand anderes kann zu schätzen wissen, die Lösung aber nicht 🙂
Wenn ein Task ist eine WinForms Komponente, es könnte sein, sehr bewusst, threading Probleme, und ruft den event handler auf der Haupt-thread -- das scheint zu sein, was Sie sehen.
So, es könnte sein, dass es stützt sich auf eine Meldung, Pumpe passiert oder so etwas. - Anwendung.Laufen hat überladungen, sind für nicht-GUI-Anwendungen. Sollten Sie erwägen, einen thread zu starten und Pumpe, um zu sehen, ob das das Problem behebt.
Ich würde auch empfehlen, mit Reflektor, um einen Blick auf den source-code der Komponente, um herauszufinden, was es tut.
Haben Sie fast bekam es. Sie müssen die DoTask Methode, um die Ausführung auf einen anderen thread, so dass die WaitOne-Aufruf wird nicht verhindern, dass die Arbeit nicht getan. So etwas wie dieses:
Mein Kommentar zu Scott W ' s Antwort scheint ein wenig kryptisch, nachdem ich es nochmals gelesen. So lassen Sie mich dies noch deutlicher:
Dem WaitOne( 200 ) bewirkt, um die Kontrolle wieder an Ihrem UI-Faden 5-mal pro Sekunde (Sie können diese anpassen, wie Sie möchten). Die DoEvents () - Aufruf wird Spülen Sie die windows event-queue (die Griffe alle windows-event-handling wie Malerei, etc.). Fügen Sie zwei Mitglieder Ihrer Klasse (ein bool-flag "fertig" in diesem Beispiel, und eine Rückkehr data "Straße" in deinem Beispiel).
Dass ist der einfachste Weg, um zu bekommen, was Sie erledigen wollen. (Ich haben einen sehr ähnlichen code in einer app für mein eigenes, damit ich weiß, dass es funktioniert)
Dein code ist fast richtig... ich habe gerade
für
TaskCompleted
ausgeführt werden, die in dem gleichen thread wieDoTask
tut. Sollte dies funktionieren.