ManualResetEvent WaitOne not unblocking
Asked Answered
S

4

5

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.
   }
}
Seminary answered 30/7, 2009 at 10:10 Comment(7)
Is your wc_DownloadFileCompeted method being called?Patrilocal
Jon, Yes it is. I'm getting right through to the Set() which is executing fine, but my main thread still blocks. The example has been simplified but if I call Set() elsewhere (for example I've got a dialog that appears, with a cancel button which also has an event. Then the Set() method in my lambda attached to this event works fine).Seminary
divo, the Set() will most likely be called by a separate thread, as I'm assuming the WebClient must create a new one to actually download the file. It's the thread that the WebClient uses to send it's event that will be calling the Set().Seminary
@Ian: Your sample works without problems when I use the code in a .NET 3.5 command line application. The problem might lie within the way your code is called or something else that happens in your code.Johnsonian
@divo, works on my machine too.Ki
Is the problem reproducible with this exact piece of code?Mephistopheles
I'm thinking there must be something else going on underneath, as there are a few other threads involved in kicking this whole process off. As yet I've not managed to isolate enough to post another example.Seminary
A
4

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.

Alphabetize answered 30/7, 2009 at 10:20 Comment(3)
Ray, I'm not sure that I follow you? My thread that calls DownloadFileAsync() should be blocking until the file has downloaded.Seminary
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.Alphabetize
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?Seminary
P
3

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 :)

Patrilocal answered 30/7, 2009 at 10:35 Comment(2)
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.Seminary
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.Seminary
G
2

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();
    } 
 } 
} 
Garibay answered 10/6, 2010 at 14:41 Comment(0)
J
1

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

Jug answered 30/7, 2009 at 10:23 Comment(2)
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.Seminary
@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!Alphabetize

© 2022 - 2024 — McMap. All rights reserved.