none
Threading, Blocking, Events, and Asynchronous Management RRS feed

  • Question

  • Alright.

    I think I have finally broken it down to what logistically could be explained for many who have trouble dealing with threads.  Naturally, of course, I don't have the answer, but I think I have the question.  Threading is always a mind boggle at times, but what is more difficult that the concept of threads is executing it in a specific framework.

    There are multiple ways to handle Threading in .Net, and my questions revolve around them all, but with specificity as to the "How to code it" as opposed to "Explain the concept."

    One method of threading:  The BeginXXX/EndXXX with IAsyncResult
    Assumed Given:  When Calling BeginXXX(CallBack) the Callback is executed on a Secondary Thread.  Thus whatever code exists within the Callback procedure must either be self-contained, thread protected (with locks etc), and/or Synchronized if being communicated to other threads (namely the calling thread).

    Another Method of Threading: Using the Thread class, and providing a TreadProc() callback method.
    Assumed Given:  The ThreadProc() method is handled similarly to the Callback of the BeginXXX/EndXXX style of threading.  The difference between the two is that the BeginXXX/EndXXX style uses the ThreadPool to manage the thread, where with the Thread Class we (the programmers) are managing the creation of the thread ourselves.

    SynchronizationContext: A wonderful utility class built into the .Net Framework for synchronizing method calls on the Calling thread. 
    AsyncOperation: A wrapper class that makes liaisons with the SynchronizationContext more amenable to the everyday programmer.
      Note:  I have rewritten this class, as it is a very simple design, with the added access to the SynchronizationContext.Send() method, which the default AsyncOperation class does not provide.

    Sync Context has two basic methods for my threading questions:  Send and Post.

    Post dispatches an Asynchronous message back to the Sync Context's Owning Thread.
    Send dispatches a Synchronous message back to the Sync Context's Owning Thread.

    Whether we use the BeginXXX/EndXXX or the Thread Class method of creating and managing a thread, the Sync Context/AsyncOperation classes are viable methods of communicating back to the calling (originating) Thread.

    Yes, this preamble is long but I think helpful to see where I am going with the actual question.
    For my example here I will use the BeginXXX/EndXXX method, the class that has these doesn't matter, because whatever class implements the IAsyncResult/Begin/End design operates the same throughout the .Net framework.

    Now let us assume (I know it can be difficult at times) that whatever our Threaded operation is, we require some form of update during the course of the operation.  Like a progress update, makes things simple.  Now, I don't know the term off the top of my head, but there is a condition that occurs when threading that causes a complete block or hangup due to both the calling thread and the worker thread waiting for the same event to be signaled.  I will give an example:
    asyncOp as MyAsyncOperation
    wait as ManualResetEvent
    
    Sub Main()
      asyncOp = MyAsyncOperation.CreateOperation(nothing)
      dim result as IAsyncResult = BeginXXX(AddressOf OperationCallback, someStateObject)
      
      wait.WaitOne()
      Do_Something_Else()
    End Sub
    
    Sub OperationCallback(result as IAsyncResult)
       dim value as object = EndXXX(result)
       while Condition
          ProcessData()
          asyncOp.Post(addressOf AsyncProgress, ProgArgs)
          'asyncOp.Send(AddressOf AsyncProgress, ProgArgs)
       End While
       wait.Set()
    End Sub
    
    Sub AsyncProgress(arg as object)
      RaiseEvent OnProgress(me, trycast(arg, ProgressEventArgs))
    End Sub
    Now, we don't need to know all of the details regarding each class, namely what object has the BeginXXX/EndXXX async operation built in, nor do we need to know the details of the ProgressEventArgs class, as we can assume it is a derivative of the EventArgs for some event. 

    What we do know by this snippet, is that the AsyncOp class (using the same model as the AsyncOperation class in the System.ComponentModel namespace) uses the calling thread's SynchronizationContext (gleaned from the AsyncOperationManager class) to dispatch messages (in the form of a method callback delegate) to the calling thread space.  So, before creating the second with the BeginXXX call, we get the current thread's SynchronizationContext in the CreateOperation() call, and then while in the worker thread, OperationCallback() method, we use the asyncOp instance to Post or Send a message back to the calling thread.

    In this situation, I am also using an Event (a Manual or Auto really doesn't matter, the specifics are for the circumstance of the programmer) to block the calling thread until the the Asynchronous operation has completed. 

    Now, I agree, some may say that this defeats the purpose of an Asynchronous operation, and in many ways they are correct.  A wiser plan would be to start the worker thread and then set up some UI loop that does not allow user input.  But for my question it is relevant to assume that maybe we do need to block the calling thread until the worker thread completes.  Perhaps for a timeout factor or an error code.  We may want to start the operation and then wait to determine if it succeeded before we proceed, and based upon the success/failure we know what to do with the result.

    The issue revolves around the WaitOne() in the Main() method and the way AsyncOperation (via SynchronizationContext) Posts or Sends the message (callback method).  Post operates asynchronously, meaning that right after the Post() call, the loop in OperationCallback keeps on ticking until the appropriate Condition is met. and the loop ends.  Meanwhile, the wait.WaitOne() has the Calling thread blocked, so even though asyncOp.Post() is posting messages to the calling thread, they aren't received. 

    Now, if in this situation we foolishly used the asyncOp.Send() method, which synchronously dispatches the message (callback method) to the calling thread, the threaded operation taking place in the OperationCallback method will block until the Send returns from the message dispatch.  Yet the situation is similar to the Post(), in that the wait.WaitOne() is currently blocking the calling thread, and thus we have deadlock.  The Send() is blocking the worker thread until the dispatch completes, while the calling thread blocks until the wait event is signaled, preventing the Send() from occurring. 

    There in lies the dilemma.  How do we create a wait state for the calling thread, that is awaiting the completion of the worker thread while simultaneously not blocking any Synchronized dispatches from the worker thread?

    As I have admitted, that this situation is not the most common situation when using asynchronous operations.  Many times I am always reviewing my design to avoid this situation of the calling thread needing to block until completion of the worker thread.  This is most often best handled by a completion event (which can be achieved through the AsyncOperation.PostOperationCompleted() method), but for some designs these operations can be occurring several classes deep, with no access to the main UI form.  I could have a Class that performs an operation, but as part of that class it calls out to another object to handle lower level processing. 
    Like a peer-to-peer file transfer across the internet would require a socket.   But so would an FTP client require a socket as well as a Web Client.  All three require a socket to handle the transfer, so in using OOP design, we'd create one Socket style class that handles the transfer from source to destination, while the individual purpose classes, being PTP, FTP, or WWW use that generic Socket class to for their individual purposes.  Thus the socket class would start and handle the transfer asynchronously, but we may have need for the UI Form to continue allowing user input for other things, while the specific PTP FTP or WWW classes need to wait for the socket to finish its operation. 

    This is not the best example, and I know many have had issue with my style of questioning since I tend to avoid specifics.  The reason for this is simple: I already know about the System.Net namespace, and do not want the "specific" question of how to perform a "specific" task answered.  I don't need the response "why don't you use HttpWebRequest" or "Why don't you use FtpWebRequest".  I am aware of these "specifics", and use them as possible examples to depict how one might desire to create a Base beneric (and i don't meadn .Net Generics) class that handles a style of operation that may be used by a multitude of other classes.  Whenever using specific examples the theory based question often gets lost, and currently I need the Theory-into-practice explained.  How does one work with the Thread model I've proposed above, where the calling thread needs to wait for the worker thread to complete, while the worker thread also needs to dispatch messages back to the calling thread.

    Thanks
    Jaeden "Sifo Dyas" al'Raec Ruiner

    PS - I have already thought of one solution I've implemented before in a specific circumstance, where I utilized nested threads.  I created one thread (with an AsyncOperation class to retain the Sync Context for the UI Thread) and from that thread, I created the secondary worker thread.  Thus the WaitOne() blocked Thread 1, while Thread 2 performed the task and signaled the Event on completion, as Thread 2 used the AsyncOperation class for Thread 0 to signal thread 0, so Thread 0 wasn't blocked, by the Event Wait in Thread 1.  Not sure if this is the only way to cleanly handle this, but it worked for my purposes in that situation, i'm just looking for a more robust method of handling similar situations in the future.





    "Never Trust a computer. Your brain is smarter than any micro-chip."
    PS - Don't mark answers on other people's questions. There are such things as Vacations and Holidays which may reduce timely activity, and until the person asking the question can test your answer, it is not correct just because you think it is. Marking it correct for them often stops other people from even reading the question and possibly providing the real "correct" answer.
    Wednesday, March 10, 2010 1:11 PM

Answers

  • Disclaimer:  I read until the question.

    There are a couple of ways that you can achieve what you want, but I honestly doesn't think is necessary.  Why?  If the calling thread is blocked, it means it is doing nothing.  If it is doing nothing, why don't you make it do the work then??  I mean, IT IS DOING NOTHING.  You don't need a new thread for sure.

    But how to do it:  Separate the code that needs to be called by the worker thread into a separate object that is not tied to the UI.  If the object is not tied to the UI, you can call its methods and properties from any thread.  You must, however, synchronize the access.

    But the above doesn't fit the progress example you posed.  But yet again, you cannot show progress if you block the UI thread!!  So the example doesn't really apply.  If you want to show progress, you must not block the UI thread (assuming it is also the calling thread) so it can maintain the UI alive for the end user.  There is just no other way around.

    Another method:  Not sure if available in .Net (I think it is not), but you could put the calling thread in an alertable wait state.  From MSDN Online:

    "The MsgWaitForMultipleObjectsEx , SignalObjectAndWait , WaitForMultipleObjectsEx , and WaitForSingleObjectEx functions differ from the other wait functions in that they can optionally perform an alertable wait operation . In an alertable wait operation, the function can return when the specified conditions are met, but it can also return if the system queues an I/O completion routine or an APC for execution by the waiting thread."

    Took from http://msdn.microsoft.com/en-us/library/ms687069%28VS.85%29.aspx.

    And I think that's about it.  I don't have any other method of accomplishing what you want.  But like I said, what you want is contradictory.  If the calling thread does nothing, then make it do the work.  If the calling thread is the UI thread, the second you block it is the second you get a non-responsive UI, and of course, no progress can be shown.
    MCP
    • Marked as answer by JaedenRuiner Thursday, March 11, 2010 2:44 PM
    Wednesday, March 10, 2010 2:40 PM

All replies

  • Disclaimer:  I read until the question.

    There are a couple of ways that you can achieve what you want, but I honestly doesn't think is necessary.  Why?  If the calling thread is blocked, it means it is doing nothing.  If it is doing nothing, why don't you make it do the work then??  I mean, IT IS DOING NOTHING.  You don't need a new thread for sure.

    But how to do it:  Separate the code that needs to be called by the worker thread into a separate object that is not tied to the UI.  If the object is not tied to the UI, you can call its methods and properties from any thread.  You must, however, synchronize the access.

    But the above doesn't fit the progress example you posed.  But yet again, you cannot show progress if you block the UI thread!!  So the example doesn't really apply.  If you want to show progress, you must not block the UI thread (assuming it is also the calling thread) so it can maintain the UI alive for the end user.  There is just no other way around.

    Another method:  Not sure if available in .Net (I think it is not), but you could put the calling thread in an alertable wait state.  From MSDN Online:

    "The MsgWaitForMultipleObjectsEx , SignalObjectAndWait , WaitForMultipleObjectsEx , and WaitForSingleObjectEx functions differ from the other wait functions in that they can optionally perform an alertable wait operation . In an alertable wait operation, the function can return when the specified conditions are met, but it can also return if the system queues an I/O completion routine or an APC for execution by the waiting thread."

    Took from http://msdn.microsoft.com/en-us/library/ms687069%28VS.85%29.aspx.

    And I think that's about it.  I don't have any other method of accomplishing what you want.  But like I said, what you want is contradictory.  If the calling thread does nothing, then make it do the work.  If the calling thread is the UI thread, the second you block it is the second you get a non-responsive UI, and of course, no progress can be shown.
    MCP
    • Marked as answer by JaedenRuiner Thursday, March 11, 2010 2:44 PM
    Wednesday, March 10, 2010 2:40 PM
  • Hrm.

    It is as I suspected.  I suppose then, the only real solution is design everything off of a flag-and-event-driven concept.  Basically making the asynchronous requests signal events (not thread events but .Net event delegates) while the UI thread is attentive to a flag that indicates the async op is still processing.  Thus allowing the ui thread to enable/disable whatever functions are not to be permitted until a success/failure report from the completion event of the async op. 

    Makes sense, though, it is a pain to code for, and cn lead to race conditions if not done properly.  Thanks for the quick reply.
    J"SD"a'RR
    "Never Trust a computer. Your brain is smarter than any micro-chip."
    PS - Don't mark answers on other people's questions. There are such things as Vacations and Holidays which may reduce timely activity, and until the person asking the question can test your answer, it is not correct just because you think it is. Marking it correct for them often stops other people from even reading the question and possibly providing the real "correct" answer.
    Wednesday, March 10, 2010 2:56 PM
  • There are a couple of ways that you can achieve what you want, but I honestly doesn't think is necessary.  Why?  If the calling thread is blocked, it means it is doing nothing.  If it is doing nothing, why don't you make it do the work then??  I mean, IT IS DOING NOTHING.  You don't need a new thread for sure.
    This is absolutely correct. If you think you need to block one thread to run a second thread, you need to rethink the problem. Show me a concrete example where it is necessary to block thread A while thread B does the work and I'll show you how to solve it without threading.
    Wednesday, March 10, 2010 3:07 PM
  • Show me a concrete example where it is necessary to block thread A while thread B does the work and I'll show you how to solve it without threading.
    You did give one example: Aborting a long-running task after a timeout period. However I would assign that problem to the task, not the executor of the task, if at all possible.
    Wednesday, March 10, 2010 4:38 PM