Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / New Users / July 2007

Tip: Looking for answers? Try searching our database.

Threading and WaitAny

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
GCeaser@aol.com - 27 Jul 2007 14:31 GMT
I am encountering a challenge while using WaitAny to detect when any
of my async processes have finished.

The scenario is I have a master class which instantiates two other
classes and calls a method on each asynchronously.  The async method
returns output that is processed via code on the main thread.

So, I have been trying to use the WaitAny passing it an array of the
WaitHandles.  I have this code in a loop that checks to see if we are
done with all async processes.  The problem with this approach is that
after the first async process comes back, and I go back through the
loop to wait for the next async process to finish (using WaitAny
again) - the same async process complete re-fires the same async item
I just processed.

If have also tried to use the AutoResetEvent in the WaitAny event --
But I can figure out how to have the methods being executed
asynchronously in my class object to call the Set method on the
AutoResetEvent to trigger my main thread to continue.

    I have also looked at the internet for some good examples of what I
am trying to do and have been unable to find any -- at least none if
VB code (and I am not too familiar with more complex C# syntax that
would be used in this type of an example.)  If anyone has a good VB
sample that I can refer to, that would be much appreciated.  It not,
the code is below.  This code us currently NOT set to use the
AutoResetEvent for the reason stated above.

Any assistance would be greatly appreciated!!!

Option Strict On
Option Explicit On

Imports GATSDataSourcesDAL
Imports System.Threading

Public Class AsynTestClass
   Private iobj_GATSDataSource As GATSDAL = Nothing
   Private iobj_GTISDataSource As GTISDAL = Nothing

   'Delegate declarations
   Private Delegate Function ReturnGATSDataSet_Delegate() As DataSet
   Private Delegate Function ReturnGTISDataSet_Delegate() As DataSet

   'Variables to create the delegates
   Private iobj_ReturnGATSDataSet_Delegate As
ReturnGATSDataSet_Delegate
   Private iobj_ReturnGTISDataSet_Delegate As
ReturnGTISDataSet_Delegate

   'Declare the results
   Private iobj_ReturnGATSDataSet_AsyncResults As IAsyncResult
   Private iobj_ReturnGTISDataSet_AsyncResults As IAsyncResult

   Private li_NumberOfDataSources As Integer = 2

   'Declare the WaitHandles Array
   Private ia_WaitHandles(li_NumberOfDataSources - 1) As WaitHandle

   'Documentation says threading items should be called from a Multi-
Threaded Appt
   <MTAThread()> _

   Public Function ReturnDataSet2() As Dictionary(Of String, DataSet)
       'This will return an array of dataset
       Dim ls_ReturnDataSet As DataSet = Nothing
       Dim lb_Done As Boolean = False
       Dim li_DoneCount As Integer
       Dim li_IX As Integer = -1
       Dim la_AsyncResults(li_NumberOfDataSources - 1) As
IAsyncResult
       Dim ls_DataSourceName As String
       Dim lobj_ReturnDictionary As Dictionary(Of String, DataSet) =
New Dictionary(Of String, DataSet)

       'Create the Data Access Layer
       iobj_GATSDataSource = New GATSDAL

       'Create and call the first asyn method
       iobj_ReturnGATSDataSet_Delegate = New
ReturnGATSDataSet_Delegate(AddressOf
iobj_GATSDataSource.ReturnDataSet)

       'Call Async to local DLL to get the data
       iobj_ReturnGATSDataSet_AsyncResults =
iobj_ReturnGATSDataSet_Delegate.BeginInvoke(Nothing, "GATS")

       'Add the async results and waithandles to the array
       li_IX += 1
       la_AsyncResults(li_IX) = iobj_ReturnGATSDataSet_AsyncResults
       ia_WaitHandles(li_IX) =
iobj_ReturnGATSDataSet_AsyncResults.AsyncWaitHandle

       'Create and call the first asyn method
       iobj_GTISDataSource = New GTISDAL

       'Create the proxy class to call the Data Access Layer
       iobj_ReturnGTISDataSet_Delegate = New
ReturnGTISDataSet_Delegate(AddressOf
iobj_GTISDataSource.ReturnDataSet)

       'Call Async to local DLL to get the data
       iobj_ReturnGTISDataSet_AsyncResults =
iobj_ReturnGTISDataSet_Delegate.BeginInvoke(Nothing, "GTIS")

       'Add the async results and waithandles to the array
       li_IX += 1
       la_AsyncResults(li_IX) = iobj_ReturnGATSDataSet_AsyncResults
       ia_WaitHandles(1) =
iobj_ReturnGTISDataSet_AsyncResults.AsyncWaitHandle

       'Wait till all the results are back of the transaction times
out
       Do Until lb_Done = True
           li_IX = WaitHandle.WaitAny(ia_WaitHandles,
TimeSpan.FromSeconds(15), False)

           'Get the correct asyncresults - Use the state to know the
object type
           ls_DataSourceName =
la_AsyncResults(li_IX).AsyncState.ToString

           Select Case ls_DataSourceName
               Case "GATS"
                   'This will get the dataset and raise any errors
                   lobj_ReturnDictionary.Add(ls_DataSourceName,
iobj_ReturnGATSDataSet_Delegate.EndInvoke(la_AsyncResults(li_IX)))
               Case "GTIS"
                   'This will get the dataset and raise any errors
                   lobj_ReturnDictionary.Add(ls_DataSourceName,
iobj_ReturnGTISDataSet_Delegate.EndInvoke(la_AsyncResults(li_IX)))
           End Select

           'Decide if we should end the loop
           li_DoneCount += 1
           If li_DoneCount > ia_WaitHandles.GetUpperBound(0) Then
               lb_Done = True
           End If

       Loop

       Return lobj_ReturnDictionary

   End Function

End Class
Peter Duniho - 27 Jul 2007 17:49 GMT
> I am encountering a challenge while using WaitAny to detect when any
> of my async processes have finished.
[quoted text clipped - 10 lines]
> again) - the same async process complete re-fires the same async item
> I just processed.

Things I don't understand about your question:

    * Why are your arrays, ia_WaitHandles and la_AsyncResults, being  
initialized to hold one fewer elements than you intend to put in them?  In  
this case, those arrays appear to be initialized to only a single element  
long.

    * Given the above, why does this line not generate an exception at  
run-time, seeing how it attempts to set the second element in an array  
that's only 1 element long:

         ia_WaitHandles(1) =
             iobj_ReturnGTISDataSet_AsyncResults.AsyncWaitHandle

    * Regardless, why do you hard-code the array index for the handle in  
the above line of code, rather than using li_IX as you do elsewhere?

And finally, this statement in your post:

> If have also tried to use the AutoResetEvent in the WaitAny event --
> But I can figure out how to have the methods being executed
> asynchronously in my class object to call the Set method on the
> AutoResetEvent to trigger my main thread to continue.

Even if I replace "I can figure" with "I can't figure" to try to make it  
make more sense, I don't understand the statement.  All you need to do is  
pass an event handle you create to the delegate doing the work somehow.  
Passing parameters to delegates isn't hard, so if you're having trouble  
doing this, you should be more specific about what problem it is you have.

All that said, it seems to me that the most direct way to fix the code  
you've got would be to just not wait on handles that have already  
completed.  You should be doing this anyway, because once you call  
EndInvoke, the wait handle you've put into the array is not guaranteed to  
be valid.  But beyond that, not waiting on a wait handle that's always  
been completed is the obvious solution to not having to deal with the wait  
handle remaining signaled.

An alternative solution would be to simply reset the event handle manually  
yourself after it's signaled.  But as I mentioned above, after calling  
EndInvoke you are not guaranteed to have a valid event handle, and so  
that's not a solution you should choose.  As an alternative to the  
alternative, you could just create a dummy WaitHandle (manual or  
auto-reset, it doesn't matter) that never gets set and replace the one you  
got from the IAsyncResult object with the dummy one, after that  
IAsyncResult gets signaled.  IMHO, that solution would be a hack and  
inappropriate in any well-written code, but it would work as well.

Pete

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.