locked
ManualResetEvent WaitAny blocking UI Thread RRS feed

  • Question

  • Hello,

    I have the following code in a class library. And I wait for a call back into my main application. I am making a DownloadStringAsync call so I have to wait a few seconds to get the callback after it has finished. I have a 3 of these calls to wait for (but for being simple just testing with one), so in my main application I am using ManualResetEvent to wait all of them to finish. So I will block until they have been set in the callback functions.

    However, after testing the callback don't get called. I am thinking when the code gets blocked by the ManualResetEvent as its blocking the DownloadStringAsync. As when I comment out this code everything works fine.

    So I think as soon as I make a call to: objNoGateway.NoGatewayStatus(sipUsername, statusDisplay1.PhoneNumber); And when the code reaches here: handle.WaitOne(); It will block the code in the class library.

    I think the main UI thread is being blocked, so cannot receive any messages.

    Many thanks for any suggestions,

    My class library:

     // Event handler that makes a call back in my main application
         // Event handler and method that handles the event
        public EventHandler<NoGatewayEventArgs> NoGatewayCompletedEvent;
        // The method that raises the event.
        private void OnNoGatewayCompleted(object sender, NoGatewayEventArgs e)
        {
            if (NoGatewayCompletedEvent != null)
            {
                NoGatewayCompletedEvent(this, e);
            }
        }
    
        // Start the Async call to find if NoGateway is true or false
        public void NoGatewayStatus(string sipUsername, string phoneNumber)
        {     
            string strURL = string.Format("http://xxxxxxxxxxxxxxx={0}&CalledNumber={1}", sipUsername, phoneNumber);
    
            if (!wc.IsBusy)
            {
                try
                {
                    string errorMsg = string.Empty;
                    wc.DownloadStringAsync(new Uri(strURL));
                }
                catch (WebException ex)
                {
                    Console.WriteLine("IsNoGateway: " + ex.Message);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("IsNoGateway: " + ex.Message);
                }
            }
            else
            {
                Console.WriteLine("WebClient: IsNoGateWay(): Busy please try again");
            }
    
        }
    
        void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                if (e.Result == "No gateway")
                {
                    OnNoGatewayCompleted(this, new NoGatewayEventArgs(validateResponse_e.VALIDATION_FAILED));
                    Console.WriteLine("NoGatway() DownloadedCompleted: " + e.Result);
                }
                else
                {
                    OnNoGatewayCompleted(this, new NoGatewayEventArgs(validateResponse_e.OK));
                    Console.WriteLine("NoGateway() DownloadCompleted: " + e.Result);
                }
            }
            else
            {
                this.OnNoGatewayCompleted(this, new NoGatewayEventArgs(validateResponse_e.SERVER_FAILED));
                Console.WriteLine("No Gateway: DownloadCompleted() Error: " + e.Error.Message);
            }
        }
    
    In my main application I register this callback. And wait for the for the result. Then set the ManualResetEvent.

     ManualResetEvent[] waitValidateCallResponse = new ManualResetEvent[] 
              { new ManualResetEvent(false), new ManualResetEvent(false), new ManualResetEvent(false) };
        // Event handler for NoGateway event
        private void OnNoGatewayCompleted(object sender, NoGatewayEventArgs e)
        {
            Console.WriteLine("OnNoGatewayComleted: " + e.noGateway);
            waitValidateCallResponse[0].Set();
        }
    Where I start and wait for the threads to finish:
    private void ValidateDialedNumber()
    {           
          //Incorrect country code has been entered.
          using (NoGateway objNoGateway = new NoGateway())
          {
                objNoGateway.NoGatewayCompletedEvent += new EventHandler<NoGatewayEventArgs>(this.OnNoGatewayCompleted);
                objNoGateway.NoGatewayStatus(sipUsername, statusDisplay1.PhoneNumber);
          }
                        
          // Block here - Wait for all reponses to finish before moving on
          //WaitHandle.WaitAll(waitValidateCallResponse);   
          waitEvent.WaitOne(5000, true);                    
          Console.WriteLine("All thread finished");
    }

















    • Edited by steve1_rm Tuesday, May 12, 2009 3:17 AM formating
    Tuesday, May 12, 2009 3:14 AM

Answers

  • The first thing that comes to mind is not necessarily a mistake, if you're prepared: inside a BackgroundWorker's DoWork event, you are not provided with a SynchronizationContext. You're setting some events and then invoking some methods on your own class - if these use the *Async/*Completed EBAP pattern, then the *Completed events will not be synchronized with any other threads (they will run on ThreadPool threads). As long as your *Completed event handlers are fully threadsafe, this won't be a problem.

    The other thing I notice is that you're "using" variables that are expected to (later) raise events. This is possible, but very unusual. Personally, I write my classes to never raise events after they've been disposed.

            -Steve
    Programming blog: http://nitoprograms.blogspot.com/
    I will be in Chicago for the WPF training: http://blogs.msdn.com/jaimer/archive/2009/04/01/announcing-the-using-wpf-to-build-lob-applications-training-tour.aspx
    • Marked as answer by Bin-ze Zhao Thursday, May 14, 2009 7:53 AM
    Wednesday, May 13, 2009 2:33 PM
  • Hello,

    This how I solved my problem using the background worker control. I haven't added all the code here as it would be too large to post (for example I haven't listed all of my callbacks as the code is very much the same). But I hope you get the general idea.

    Any comments on any mistakes I have made would be most grateful.

    Many thanks,

    // This is started by clicking a button
    private void bgwPrepareCall_DoWork(object sender, DoWorkEventArgs e)
    {
    // These are calls to DownloadStringAsync - wait for call back and set the wait handler
    using (NoGateway objNoGateway = new NoGateway())
    {
    objNoGateway.NoGatewayCompletedEvent += new EventHandler<NoGatewayEventArgs>(this.OnNoGatewayCompleted);
    objNoGateway.NoGatewayStatus(sipUsername, statusDisplay1.PhoneNumber);
    }
    using (CalledNumberBlocked objCalledNumberBlocked = new CalledNumberBlocked())
    {
    objCalledNumberBlocked.CalledNumberBlockedEvent += new EventHandler<CalledNumberBlockedEventArgs>(this.OnCalledNumberBlockedCompleted);
    objCalledNumberBlocked.CalledNumberBlockedStatus(sipUsername, this.statusDisplay1.PhoneNumber);
    }
    // There is more, but I won't list them here

    // Wait for all them to finish
    Console.WriteLine("Wait here until all threads have finished......");
    foreach (WaitHandle handle in waitValidateCallResponse)
    {
    WaitHandle.WaitAny(waitValidateCallResponse);
    }
    Console.WriteLine("All threads finished");
    }
    private void bgwPrepareCall_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
    if (e.Error == null)
    {
    if (!e.Cancelled)
    {
    // Successfull continue with phone call
    this.statusDisplay1.CallStatus = CATWinSIP_MsgStrings.Calling;
    this.MakeCall(string.Empty, statusDisplay1.PhoneNumber, false);
    }
    }
    else
    {
    Console.WriteLine("PrepareCall Failed: [ " + e.Error.Message + " ]");
    }
    }
    My call backs from the DownloadStringAsync that set the wait events after the DownStringAsync have completed

    AutoResetEvent[] waitValidateCallResponse = new AutoResetEvent[]
    { new AutoResetEvent(false), new AutoResetEvent(false) };
    // Event handler for NoGateway event
    private void OnNoGatewayCompleted(object sender, NoGatewayEventArgs e)
    {
    Console.WriteLine("OnNoGatewayComleted: " + e.noGateway);
    waitValidateCallResponse[0].Set();
    }
    // Event handler for CalledNumberBlocked event
    private void OnCalledNumberBlockedCompleted(object sender, CalledNumberBlockedEventArgs e)
    {
    Console.WriteLine("OnCalledNumberBlockedCompleted: " + e.CalledNumberBlocked);
    waitValidateCallResponse[1].Set();
    }



    • Marked as answer by Bin-ze Zhao Thursday, May 14, 2009 7:53 AM
    Wednesday, May 13, 2009 2:23 PM

All replies

  • I'm not familiar with DownloadStringAsync -- does it actually spin off its own thread, or does it just put an event hook into the application's message sink? If it doesn't run its own thread, then WaitOne, by virtue of its blocking of the thread its executed within will be blocking the *only* thread...hence a lock state. Someone with more knweldge of DownloadStringAsync could probably give you the low-down, but personally i'd probably spin the workers/flags off into their own threads. My hunch is that will solve your problem, and at the very least will keep your GUI from performing in a punch-drunk manner...
    Tuesday, May 12, 2009 4:37 AM
  • You are correct: any *Async/*Completed API pairs use what's called the Event-Based Asynchronous Pattern (EBAP). The way they raise their events is to queue a message to the GUI thread; this prevents most multithreading issues, since the events are invoked on the GUI thread.

    The problem is that you don't want to block the GUI thread. Instead, keep a state to track which or how many operations have completed (three booleans or a counter). Then, when the operations begin, disable parts of your GUI (so the user can't initiate them again, which would be bad) - or just disable the whole form and throw up a progressbar form. When the last operation completes, process the results and re-enable those parts of the GUI. This additional statekeeping is unfortunate but necessary when using asynchronous designs.

    You probably do not want to move the *Async part to another thread; since independent threads don't have message queues, the *Completed event will be raised on a ThreadPool thread instead of the GUI thread.

            -Steve
    Programming blog: http://nitoprograms.blogspot.com/
    I will be in Chicago for the WPF training: http://blogs.msdn.com/jaimer/archive/2009/04/01/announcing-the-using-wpf-to-build-lob-applications-training-tour.aspx
    Tuesday, May 12, 2009 11:04 AM
  • Steve,

    Not to get sidetracked from resolving steve1_rm's issue, but in the interest of educating the rest of us not too knoweledgeable on .net's mechanics:

    Q: do most/all of the .Net components that handle Async mesaging via the EBAP pattern, or do any of them actually wrap their own internal threadProc's and/or message sinks? (i.e., do any of them rely on COM built-in's or even the shell window-class "msg" ?)

    Q: (along the same lines) are there any Async controls within .net that developers do *not* have to deal with potential blocking/locking issues?

    thanks for the insight,
    -mjk


    Tuesday, May 12, 2009 1:45 PM
  • Hello,

    Thanks for the responses. 

    Its also good to learn more about EBAP, STD and MTD. As I have learnt that windows GUI only supports STD. 

    However, back to my problem and along the lines of what mjk said.   

    From msdn documentation:
      Name Description
    Public method DownloadStringAsync(Uri) Downloads the resource specified as a Uri . This method does not block the calling thread.
    Public method DownloadStringAsync(Uri, Object) Downloads the specified string to the specified resource. This method does not block the calling thread.


    I don't think I can use this design with Async's as while the GUI has been blocked from receiving any messages. I guess a deadlock will ensure.

    So, I guess I could create another thread and then call the functions from it, I am not at my computer so I am just guessing.

    So the following will be called from another thread and not from the GUI thread. And I would set them in my callback functions as normal. Would that solve the problem?
    Thread th = new Thread(new ThreadStart(startCnnProcess));
    th.Start();


    void startCnnProcess()
    {
    using (NoGateway objNoGateway = new NoGateway())
    {
    objNoGateway.NoGatewayCompletedEvent += new EventHandler<NoGatewayEventArgs>(this.OnNoGatewayCompleted);
    objNoGateway.NoGatewayStatus(sipUsername, statusDisplay1.PhoneNumber);
    }
    .
    .
    .
    .
    .
    .

    //Wait and block here for all 3 jobs to finish
    WaitHandle.WaitAll(waitValidateCallResponse);

    }

    Many thanks,

    Tuesday, May 12, 2009 4:40 PM
  • Why are you blocking your GUI thread?

           -Steve
    Programming blog: http://nitoprograms.blogspot.com/
    I will be in Chicago for the WPF training: http://blogs.msdn.com/jaimer/archive/2009/04/01/announcing-the-using-wpf-to-build-lob-applications-training-tour.aspx
    Tuesday, May 12, 2009 5:10 PM
  • Steve,

    Not to get sidetracked from resolving steve1_rm's issue, but in the interest of educating the rest of us not too knoweledgeable on .net's mechanics:

    Q: do most/all of the .Net components that handle Async mesaging via the EBAP pattern, or do any of them actually wrap their own internal threadProc's and/or message sinks? (i.e., do any of them rely on COM built-in's or even the shell window-class "msg" ?)

    Q: (along the same lines) are there any Async controls within .net that developers do *not* have to deal with potential blocking/locking issues?

    thanks for the insight,
    -mjk



    A: AFAIK, none of the .NET EBAP APIs have their own child threads, nor do they use message windows. Of the ones that I've looked at (which are all logically some form of request/reply), they usually initiate an I/O bound operation - such as a network request - and use the ThreadPool to monitor for a reply I/O event. The reply handler running on the ThreadPool then queues the proper event handler to run on the original thread.

    That last step is where SynchronizationContext comes into play. It's usually captured in the *Async function and then used by the ThreadPool handler to queue the actual *Completed event handler to run on the GUI thread. The SynchronizationContext is the object that handles the cross-thread invoking; for Windows Forms, it uses a windows message.

    So, EBAP components don't have their own threads; they don't need to. They use the ThreadPool as necessary (usually just to wait for I/O operations to complete). All the cross-thread invoking is one-way, from the ThreadPool to the original thread.

    A: EBAP was designed for ease-of-use. There are usually no blocking/locking issues with EBAP, since it's handled all behind the scenes. The only problems are in situations such as when a coder tries to initiate the same operation more than once; most EBAP objects don't support this.

    EBAP does imply an asynchronous design, so this require more statekeeping. However, this state does not have locking issues.

             -Steve
    Programming blog: http://nitoprograms.blogspot.com/
    I will be in Chicago for the WPF training: http://blogs.msdn.com/jaimer/archive/2009/04/01/announcing-the-using-wpf-to-build-lob-applications-training-tour.aspx
    Tuesday, May 12, 2009 5:42 PM
  • Steve: thanks for taking the time to share your insights into .net's Async model. I, for one, appreciate the lesson.

    Steve1_rm: as Steve pointed out, I'd figure out an architecture where you're not blocking the main (and presumably GUI thread). I've heard it called a number of things but I generally just call it a hub/spoke model. The pokes are spin-off processes (be they workers, state-watchers, or event handlers) while your primary thread serves as the Hub. The hub needs its own message pump/event sink so that you're not running it straight into a wall. If your app has a centralized Form (which all contain its own wndProc/sink) then doing something like Application.Run(MyMainGuiForm) after you've spun off the worker threads will suffice. That's generally the "model" that I use for multi-threading, and of course, it can made made as intricate as your particular situation merits.

    The other idea would be to spin the UI (Form) handlers  off into separate threads (you can determine their priority level as needed) and then put your main thread into thread-proc loop incorporating something like DoEvents() so that the events/messages queued by your Async object can be processed. (I.e., in place of your WaitAll statement).

    -mjk

    Tuesday, May 12, 2009 10:23 PM
  • Hello,

    Thanks for the info on the hub/spoke model concept.

    However, its difficult to see without actually seeing any code samples.

    Could you possibly direct me to any links (especially for a beginner) or give me a skeleton sample that I can apply to my own problem.

    Many thanks,

     
    Wednesday, May 13, 2009 12:29 AM
  • The question I asked, "Why are you blocking your GUI thread?", when answered, will give a direction to the solution. -Steve
    Programming blog: http://nitoprograms.blogspot.com/
    I will be in Chicago for the WPF training: http://blogs.msdn.com/jaimer/archive/2009/04/01/announcing-the-using-wpf-to-build-lob-applications-training-tour.aspx
    Wednesday, May 13, 2009 2:33 AM
  • This gentleman has a pretty nice synopsis of Threading:

    http://www.c-sharpcorner.com/UploadFile/mgold/MultithreadingIntro10062005000439AM/MultithreadingIntro.aspx?ArticleID=920ecafc-e83b-4a9c-a64d-0b39ad885705

    It's billed as an introduction, but considering the amount to detail associated with threading, I'd classify that content as a step beyond. That's about all I can think of as far a into material. I'm certain that if you post a request on the board that you'll get some extremely good guidance....there's some pretty sharp developers hanging out here.

    Hub/spoke, bus, or whatever term you hear it called, is not anything new or ground breaking. It's just a way to conceptualize what's happening. That's all. Your earlier example is basically the concept, except for running the Main thread into a dead-end (block/lock). Replace what that with some type of "breathing" message sink and you should be fine.


    For example, using your earlier code: Assuming that you do this from within a Form (or other place that has a message sink)

    int cEventCounter = 0;
    event GoBabyGo; // <-- whatever delegate/event you wanted to utlilize
    void Initialize_AsyncProcesses()
    {
    GoBabyGo = new SystemEventHandler(this.DoSomethingSmart);
    CreateSomeAsyncObject(parameter1); // <--- 3 of these, is that right?
    CreateSomeAsyncObject(parameter2); // when you get an individual "OK" then increment "cEventCounter"
    CreateSomeAsyncObject(parameter3);
    Thread inspector = new Thread(this.Inspect);
    inspector.Start(); // set to low priority if need be
    }
    void Inspect()
    {
    // do some type of look/sleep cycle until
    while (3 != cEventCounter) // however many Ok's you need to wait for
    {
    // listen, then sleep a while
    }
    // all Flags are G.O. so fire off an event..
    GoBabyGo();
    // thread shutdown/clean-up code goes here
    }
    void DoSomethingSmart()
    {
    DoFoo();
    MoreFoo();
    }
    It's crude, and probably full of typos, but you'll get the idea. I usually wrap threads into self-contained classes, but that's just my personal preference. If I'm understanding Steve's breakdown of .net's EBAP model, then this should work fine for you...

    Wednesday, May 13, 2009 3:04 AM
  • Hello,

    The question "why are you blocking the GUI thread?" Well actually I am not trying to block the GUI thread.

    My idea is that the GUI should remain responsive while waiting for all threads to finish. 

    Once the threads have finished the program can continue with is background operation. However, the GUI should remain responsive throughout this.

    I am working on a solution myself that uses the background worker, and I am taking a look at the solution posted by mjk. But I would like to know how you would solve this problem, I think everyone would.

    Many thanks,

    Wednesday, May 13, 2009 8:45 AM
  • Here is another great website I found about threading. Incase anyone else should stubble on to this post.

    http://www.albahari.com/threading/

    Thanks,
    Wednesday, May 13, 2009 8:46 AM
  • You are wanting the GUI thread to wait for all operations to complete (otherwise, there wouldn't be a wait in there at all). I am assuming that this is because there is some button - "Go On" or whatever - that shouldn't be pushed until all the operations are complete.

    Keep a state to track which or how many operations have completed (three booleans or a counter). Then, when the operations begin, disable the "Go On" button. When the last operation completes, process the results and re-enable the "Go On" button. This additional statekeeping is unfortunate but necessary when using asynchronous designs.

    That's how I would do it.

            -Steve
    Programming blog: http://nitoprograms.blogspot.com/
    I will be in Chicago for the WPF training: http://blogs.msdn.com/jaimer/archive/2009/04/01/announcing-the-using-wpf-to-build-lob-applications-training-tour.aspx
    Wednesday, May 13, 2009 11:22 AM
  • Hello,

    This how I solved my problem using the background worker control. I haven't added all the code here as it would be too large to post (for example I haven't listed all of my callbacks as the code is very much the same). But I hope you get the general idea.

    Any comments on any mistakes I have made would be most grateful.

    Many thanks,

    // This is started by clicking a button
    private void bgwPrepareCall_DoWork(object sender, DoWorkEventArgs e)
    {
    // These are calls to DownloadStringAsync - wait for call back and set the wait handler
    using (NoGateway objNoGateway = new NoGateway())
    {
    objNoGateway.NoGatewayCompletedEvent += new EventHandler<NoGatewayEventArgs>(this.OnNoGatewayCompleted);
    objNoGateway.NoGatewayStatus(sipUsername, statusDisplay1.PhoneNumber);
    }
    using (CalledNumberBlocked objCalledNumberBlocked = new CalledNumberBlocked())
    {
    objCalledNumberBlocked.CalledNumberBlockedEvent += new EventHandler<CalledNumberBlockedEventArgs>(this.OnCalledNumberBlockedCompleted);
    objCalledNumberBlocked.CalledNumberBlockedStatus(sipUsername, this.statusDisplay1.PhoneNumber);
    }
    // There is more, but I won't list them here

    // Wait for all them to finish
    Console.WriteLine("Wait here until all threads have finished......");
    foreach (WaitHandle handle in waitValidateCallResponse)
    {
    WaitHandle.WaitAny(waitValidateCallResponse);
    }
    Console.WriteLine("All threads finished");
    }
    private void bgwPrepareCall_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
    if (e.Error == null)
    {
    if (!e.Cancelled)
    {
    // Successfull continue with phone call
    this.statusDisplay1.CallStatus = CATWinSIP_MsgStrings.Calling;
    this.MakeCall(string.Empty, statusDisplay1.PhoneNumber, false);
    }
    }
    else
    {
    Console.WriteLine("PrepareCall Failed: [ " + e.Error.Message + " ]");
    }
    }
    My call backs from the DownloadStringAsync that set the wait events after the DownStringAsync have completed

    AutoResetEvent[] waitValidateCallResponse = new AutoResetEvent[]
    { new AutoResetEvent(false), new AutoResetEvent(false) };
    // Event handler for NoGateway event
    private void OnNoGatewayCompleted(object sender, NoGatewayEventArgs e)
    {
    Console.WriteLine("OnNoGatewayComleted: " + e.noGateway);
    waitValidateCallResponse[0].Set();
    }
    // Event handler for CalledNumberBlocked event
    private void OnCalledNumberBlockedCompleted(object sender, CalledNumberBlockedEventArgs e)
    {
    Console.WriteLine("OnCalledNumberBlockedCompleted: " + e.CalledNumberBlocked);
    waitValidateCallResponse[1].Set();
    }



    • Marked as answer by Bin-ze Zhao Thursday, May 14, 2009 7:53 AM
    Wednesday, May 13, 2009 2:23 PM
  • The first thing that comes to mind is not necessarily a mistake, if you're prepared: inside a BackgroundWorker's DoWork event, you are not provided with a SynchronizationContext. You're setting some events and then invoking some methods on your own class - if these use the *Async/*Completed EBAP pattern, then the *Completed events will not be synchronized with any other threads (they will run on ThreadPool threads). As long as your *Completed event handlers are fully threadsafe, this won't be a problem.

    The other thing I notice is that you're "using" variables that are expected to (later) raise events. This is possible, but very unusual. Personally, I write my classes to never raise events after they've been disposed.

            -Steve
    Programming blog: http://nitoprograms.blogspot.com/
    I will be in Chicago for the WPF training: http://blogs.msdn.com/jaimer/archive/2009/04/01/announcing-the-using-wpf-to-build-lob-applications-training-tour.aspx
    • Marked as answer by Bin-ze Zhao Thursday, May 14, 2009 7:53 AM
    Wednesday, May 13, 2009 2:33 PM