2009-07-30 17 views
4

Ich bin ein wenig verwirrt über ein ManualResetEvent, das ich verwende, die nicht zu entsperren scheint. Wer weiß, warum dies der Fall sein könnte?ManualResetEvent WaitOne nicht entsperren

Das Szenario, das ich habe, ist etwas in dieser Richtung. Die tatsächliche Situation ist ziemlich kompliziert und es ist mir nicht gelungen, einen Codeabschnitt zu isolieren, der posten kann, um das Problem zu reproduzieren.

BEARBEITEN
Ich habe das Codebeispiel unten aktualisiert. Dies wird in einer Reihe von verschiedenen Dialogen ausgeführt und ich habe festgestellt, dass einer von ihnen die this.mre.WaitOne() trifft; Dann, was passiert ist, bekomme ich einen "Server Busy" -Dialog, wo ich auf "Switch to" oder "Retry" drücken muss, was meinem Code erlaubt, den WaitOne() - Aufruf zu bestehen und alles wird funktionieren. Ich bin mir nicht sicher, wie es relevant ist, aber offensichtlich ist es wichtig.

+0

Ist Sie 'wc_DownloadFileCompeted' Methode aufgerufen wird? –

+0

Jon, ja, ist es. Ich komme direkt zu Set(), das gut ausgeführt wird, aber mein Haupt-Thread blockiert immer noch. Das Beispiel wurde vereinfacht, aber wenn ich Set() an anderer Stelle aufrufen (zum Beispiel habe ich einen Dialog, mit einem Abbrechen-Button, der auch ein Ereignis hat. Dann die Set() -Methode in meinem Lambda diesem Ereignis beigefügt funktioniert gut). – Ian

+0

divo, das Set() wird höchstwahrscheinlich von einem separaten Thread aufgerufen, da ich davon ausgehe, dass der WebClient einen neuen erstellen muss, um die Datei tatsächlich herunterzuladen. Es ist der Thread, den der WebClient verwendet, um sein Ereignis zu senden, das Set() aufrufen wird. – Ian

Antwort

4

Webclient läuft im selben Thread wie Ihr Aufrufer, so dass Thread an der WaitOne blockiert ist, es erstellt tatsächlich keinen neuen Thread für Sie.

Verschieben Sie Ihren Code in einen BackgroundWorker oder einfach, blockieren Sie nicht, sondern warten Sie, bis das DownloadComplete-Ereignis ausgelöst wird.

+1

Ray, ich bin mir nicht sicher, ob ich dir folge? Mein Thread, der DownloadFileAsync() aufruft, sollte blockiert werden, bis die Datei heruntergeladen wurde. – Ian

+0

Ihr Code läuft alle in einem einzigen Thread (versuchen Sie, Debug-Traces mit der Thread-ID zu bestätigen), dh Sie versuchen zu "Warten" und führen Sie den WebClient-Download zur gleichen Zeit aus. Die interne Planung kann tun, was Sie wollen, oder Sie können Fehler bekommen, wie Sie bekommen. Wenn Sie warten müssen, rufen Sie entweder die Async-Version der Methode nicht auf (das wäre dann eine implizite Wartezeit), oder machen Sie sie zu einer echten Multithread-Anwendung. –

+0

Ich habe mein Beispiel etwas aktualisiert.Ich bin mir nicht sicher, ob die UI-Ereignisse verarbeitet werden. Ich erwarte, dass sie in dem neu erstellten Thread sein werden, wenn FormB angezeigt wird. Ehrlich gesagt bin ich mir nicht sicher, wie sich das auf das ResetEvent bezieht, das nicht ausgelöst wird? Oder fehlt mir etwas? – Ian

1

Warum wc.DownloadFile statt wc.DownloadFileAsync nicht, wenn Sie es wollen sowieso blockieren ..

+0

Da die WebClient-Ereignisse nur beim asynchronen Download verfügbar sind und ich die Download-Informationen dem Benutzer anzeigen möchte, blockieren Sie den weiteren Fortschritt meiner App, bis ich sicher bin, dass die Datei zum Öffnen verfügbar ist. – Ian

+0

@Ian, aber Sie blockieren auch Ihre GUI zu ... Sie wissen, dass die Datei im DownloadComplete-Ereignis verfügbar ist, also verschieben Sie Ihren Post-WaitOne-Code in den Event-Handler! –

3

Prüfen, ob die MRE Sie Einstellung eigentlich das gleiche MRE ist Sie warten auf. Sie sagen, dies ist ein vereinfachtes Beispiel - ist es möglich, dass Sie in dem echten Code zwei verschiedene Reset-Ereignisse erstellen? Das würde ganz offensichtlich Dinge kaputt machen :)

+0

Jon, die MREs sind gleich. Überprüft das früher. Ich versuche nur zu sehen, ob ich den eigentlichen Code vereinfachen kann, weil es ziemlich kompliziert ist. – Ian

+0

Habe versucht, die Code-Struktur zu aktualisieren. Unglücklicherweise sind 3/4 Klassen involviert, die alle Arten von Ereignissen und Delegaten verwenden, was ich für ziemlich trivial halte, aber für ein viel umfassenderes Beispiel benötigt werden. – Ian

2

Ich habe deinen Code ein bisschen modifiziert und es wird funktionieren wie jetzt soll. Das Problem war, dass Sie sollten das MRE-Objekt als Benutzer Zustandsparameter der DownloadFileAsync Methode übergeben:

public class A 
{ 
public void Start(ThreadClass tc) 
{ 
    ManualResetEvent mre = new ManualResetEvent(false); 
    WebClient wc = new WebClient(); 
    // progress events are pumped to the ThreadClass which then update the Form2. 
    wc.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(wc_DownloadFileCompleted); 

    wc.DownloadFileAsync("Src", "Tgt", mre); 
    mre.WaitOne(); 
    mre.Close(); 
} 

void void wc_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) 
{ 
    try 
    { 
    // Do Stuff 
    } 
    finally 
    { 
     (e.UserState as ManualResetEvent).Set(); 
    } 
} 
}