Consider this code:
class Program
{
static void Main(string[] args)
{
Master master = new Master();
master.Execute();
}
}
class TestClass
{
public void Method(string s)
{
Console.WriteLine(s);
Thread.Sleep(5000);
Console.WriteLine("End Method()");
}
}
class Master
{
private readonly TestClass test = new TestClass();
public void Execute()
{
Console.WriteLine("Start main thread..");
Action<String> act = test.Method;
IAsyncResult res = act.BeginInvoke("Start Method()..", x =>
{
Console.WriteLine("Start Callback..");
act.EndInvoke(x);
Console.WriteLine("End Callback");
}, null);
Console.WriteLine("End main thread");
Console.ReadLine();
}
}
We have result:
Start main thread..
End main thread
Start Method()..
End Method()
Start Callback..
End Callback
So, I want result:
Start main thread..
Start Method()..
End Method()
Start Callback..
End Callback
End main thread
How can I wait async
in this code? I checked MSDN article "Calling Synchronous Methods Asynchronously" and found this:
After calling BeginInvoke
you can do the following:
- Do some work and then call
EndInvoke
to block until the call completes. - Obtain a
WaitHandle
using theIAsyncResultAsyncWaitHandle
property, use itsWaitOne
method to block execution until the
WaitHandle
is signaled, and then callEndInvoke
. - Poll the
IAsyncResult
returned byBeginInvoke
to determine when the asynchronous call has completed, and then callEndInvoke
. - Pass a delegate for a callback method to
BeginInvoke
. The method is executed on aThreadPool
thread when the asynchronous call completes. The callback method callsEndInvoke
.
I think better variant for me this second. But how implement this? In particular I'm interested overload WaitOne()
(Blocks the current thread until the current WaitHandle receives a signal). How correctly do it? I mean the common pattern in this case.
UPDATE:
Now I use Task<T>
:
class Program
{
static void Main(string[] args)
{
Master master = new Master();
master.Execute();
}
}
class WebService
{
public int GetResponse(int i)
{
Random rand = new Random();
i = i + rand.Next();
Console.WriteLine("Start GetResponse()");
Thread.Sleep(3000);
Console.WriteLine("End GetResponse()");
return i;
}
public void SomeMethod(List<int> list)
{
//Some work with list
Console.WriteLine("List.Count = {0}", list.Count);
}
}
class Master
{
private readonly WebService webService = new WebService();
public void Execute()
{
Console.WriteLine("Start main thread..");
List<int> listResponse = new List<int>();
for (int i = 0; i < 5; i++)
{
var task = Task<int>.Factory.StartNew(() => webService.GetResponse(1))
.ContinueWith(x =>
{
Console.WriteLine("Start Callback..");
listResponse.Add(x.Result);
Console.WriteLine("End Callback");
});
}
webService.SomeMethod(listResponse);
Console.WriteLine("End main thread..");
Console.ReadLine();
}
}
Main problem this is SomeMethod()
gets empty list
.
Result:
Now I have monstrous solution :(
public void Execute()
{
Console.WriteLine("Start main thread..");
List<int> listResponse = new List<int>();
int count = 0;
for (int i = 0; i < 5; i++)
{
var task = Task<int>.Factory.StartNew(() => webService.GetResponse(1))
.ContinueWith(x =>
{
Console.WriteLine("Start Callback..");
listResponse.Add(x.Result);
Console.WriteLine("End Callback");
count++;
if (count == 5)
{
webService.SomeMethod(listResponse);
}
});
}
Console.WriteLine("End main thread..");
Console.ReadLine();
}
Result:
That's what I need to wait for the asynchronous call. How can I use Wait
for Task
here?
UPDATE 2:
class Master
{
private readonly WebService webService = new WebService();
public delegate int GetResponseDelegate(int i);
public void Execute()
{
Console.WriteLine("Start main thread..");
GetResponseDelegate act = webService.GetResponse;
List<int> listRequests = new List<int>();
for (int i = 0; i < 5; i++)
{
act.BeginInvoke(1, (result =>
{
int req = act.EndInvoke(result);
listRequests.Add(req);
}), null);
}
webService.SomeMethod(listRequests);
Console.WriteLine("End main thread..");
Console.ReadLine();
}
}
I assume that is what you want. We are starting tasks and then waiting them to complete, after all are completed, we are getting results.
Ugly solution with BeginIvoke/EndInvoke