WaitHandle class
WaitHandle class in System.Threading namespace comes to
our rescue in these scenarios to detect the completion signal from the
asynchronous thread and complete the data binding.
WaitHandle class has 2 methods that take array of
WaitHandle objects,
Listing 4 - WaitHandle methods
WaitHandle.WaitAll()
WaitHandle.WaitAny()
WaitHandle.SignalAndWait()
The first method WaitAll() will wait for all the
asynchronous operation to complete and return a Boolean indicating the
completion of all the opeartion while next method WaitAny() will gives us any
one index of WaitHandle array indicating that it is completed. SignalAndWait()
method signals one WaitHandle object and waits on another, as an atomic
operation. Most commonly used methods are WaitAll() and WaitAny().
For making this work we need the WaitHandle object of
each asynchronous operation. The IAsyncResult object which is returned by Begin
method has a property called AsyncWaitHandle that will give us WaitHandle object
to know the completion of the current asynchronous operation. Refer the code
below.
Listing 5 - WaitHandle methods
IAsyncResult ar1 = com1.BeginExecuteReader();
WaitHandle handles = ar1.AsyncWaitHandle;
The next section will explain the use of WaitHandle
object in detail.
Using WaitHandle Object
Refer the example code with this article to have a
better understanding.
Listing 5 - WaitHandle implementation
try
{
con1 = new
SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
con1.Open();
com1 = new SqlCommand("SELECT emp_id, fname,
lname, job_id, hire_date FROM employee ORDER BY emp_id, fname",
con1);
con2 = new
SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
con2.Open();
com2 = new SqlCommand("waitfor delay
'00:00:06';SELECT * FROM Authors", con2);
con3 = new
SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
con3.Open();
com3 = new SqlCommand("waitfor delay
'00:00:06';SELECT * from Department", con3);
IAsyncResult ar1 =
com1.BeginExecuteReader();
IAsyncResult ar2 =
com2.BeginExecuteReader();
IAsyncResult ar3 =
com3.BeginExecuteReader();
WaitHandle[] handles = new WaitHandle[3];
handles[0] = ar1.AsyncWaitHandle;
handles[1] = ar2.AsyncWaitHandle;
handles[2] = ar3.AsyncWaitHandle;
for (int results = 0; results <
handles.GetLength(0); results++)
{
// wait for any handle, then process
results as they come
int index = WaitHandle.WaitAny(handles,
8000, false); // 8 secs
if (WaitHandle.WaitTimeout == index)
throw new Exception("Timeout
Exception");
if (index == 0)
{
dr1 = com1.EndExecuteReader(ar1);
gvEmployee.DataSource = dr1;
}
else if (index == 1)
{
dr2 = com2.EndExecuteReader(ar2);
gvAuthors.DataSource = dr2;
}
else if (index == 2)
{
dr3 = com3.EndExecuteReader(ar3);
gvDepartment.DataSource = dr3;
}
}
Page.DataBind();
}
catch
{
throw;
}
finally
{
dr1.Close();
com1.Dispose();
con1.Close();
dr2.Close();
com2.Dispose();
con2.Close();
dr3.Close();
com3.Dispose();
con3.Close();
}
The above code (Listing 5 - WaitHandle implementation)
uses WaitHandle.WaitAny() method and populates data asynchronously and binds 3
gridviews. If we see this line,
Listing 6 - WaitHandle in action
int index = WaitHandle.WaitAny(handles, 8000, false);
Here 8000 indicates that after 8000 milli seconds if no
completed signal is received then it is said to be reached timeout.
WaitHandle.WaitTimeout property will gives us the index of the WaitHandle object
in the array indicating that it has reached the timeout.
Callback delegate
One of the overload of begin method will accept a
delegate argument with a state object to detect the completion. Once the
database operation is complete ADO.Net will call the delegate and the state can
be accessed by IAsyncResult object.
Listing 7 - Callback delegate
BeginExecuteReader(AsyncCallback callback, object
state)
The call back method should accept IAsyncResult as
argument and call the End method.
Visit the Keyvan’s blog in reference section to see the
implementation of callback delegate.
Polling
The completion signal can also detected by a method
called IsCompleted() in IAsyncResult which returns a Boolean indicating that the
operation is completed.
Cancel the execution
For some reasons or business condition if we like to
cancel the operation we can call Cancel() method packed with the command
object.
Things to consider
Since the database operation is executed in a separate
thread if an exception occurs the operation is signaled as complete and the
actual exception will be thrown if we call End method. So we have to make sure
that we are having proper exception handling code in this scenario.
|