views:

937

answers:

4

I'm a little confused over a ManualResetEvent that I'm using which doesn't appear to be unblocking. Anyone know why this might be the case?

The scenario I've got is something along these lines. The real situation is quite complicated and I've not managed to isolate a section of code that's reasonable to post to reproduce the issue.

EDIT
I've updated the code example below. This is execute in a number of different dialogs and I have noticed that one of them hits the this.mre.WaitOne(); Then what happens is I get a "Server Busy" dialog, where I need to press 'switch to' or 'retry', which will then allow my code to step passed the WaitOne() call and all will work. I'm not sure how its relevant, but obviously its of some important.

public class A
{
 ManualResetEvent mre;

 public void Start(ThreadClass tc)
 {
    this.mre = new ManualResetEvent(false);
    tc.Begin();

    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");
    this.mre.WaitOne();
 }

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

public class ThreadClass
{
   Begin()
   {
      Thread t = new Thread(new ThreadStart(DoWork));
      t.Start();
   }

   private void DoWork()
   {
     Form f = new Form2();
     f.ShowDialog();

     // Sits waiting on another ResetEvent to determine when to close the thread.
   }
}
+3  A: 

Webclient runs in the same thread as your caller, so that thread is blocked at the WaitOne, it doesn't actually create a new thread for you.

Move your code into a BackgroundWorker or simply, don't block but wait for the DownloadComplete event to be raised.

Ray Hayes
Ray, I'm not sure that I follow you? My thread that calls DownloadFileAsync() should be blocking until the file has downloaded.
Ian
Your code is all running in a single thread (try putting debug traces with the thread ID to confirm), that means you are trying to "Wait" and execute the WebClient download at the same time. The internal scheduling may do what you want, or you may start getting errors like you're getting. If you need to wait, either do not call the Async version of the method (that would then be an implicit wait) or make it a true multithreaded application.
Ray Hayes
I've updated my example slightly. I'm not exactly sure the UI events get processed. I expect that they'll be on the newly created thread when FormB is displayed.Honestly I'm not sure how that relates to the ResetEvent not being trigger though? Or am I missing something?
Ian
+1  A: 

Why not use wc.DownloadFile instead of wc.DownloadFileAsync if you want it to block anyways..

Zyphrax
Because the WebClient events are only available when downloading asynchronously, and I wish to display download information back to the user, yet block any further progress of my app until I can be sure that the file is available to open.
Ian
@Ian, but you are also blocking your GUI too... you know the file is available in the DownloadComplete event, so move your post-WaitOne code to inside the event handler!
Ray Hayes
+2  A: 

Check that the MRE you're setting is actually the same MRE you're waiting on. You say this is a simplified example - is it possible that in the real code you're creating two different reset events? That would fairly obviously break things :)

Jon Skeet
Jon, the MRE's are the same. Checked that one earlier. Just trying to see if I can simplify the actual code because its quite involved.
Ian
Have tried to put an update to the code structure. Unfortuanetly there are 3/4 classes involved using all sorts of events and delegates which I think are pretty trivial but are required for a much fuller example.
Ian
+1  A: 

I have modified your code a bit and it will work as supposed to now. The problem was that you should have passed the MRE object as the user state parameter of the DownloadFileAsync method:

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();
    } 
 } 
} 
Dimitar Paskov