I have asynchrounous function that accepts callback
void requestSomething (Action callback)
I need to run it several times and run MainCallback
after all functions has finished
for (int i=0;i<5;i++)
requestSomething (singleCallback);
I imagine how to do this with counter that counts for 5 times and then runs mainCallback, but I believe there is a better way for doing this.
edit:
I can do it this way:
int counter = 5;
for (int i=0;i<counter;i++)
{
requestSomething (()=> { counter--;开发者_Go百科
if (counter == 0)
mainCallback()} );
}
Is there a better way to implement this logic?
You can encapsulate callback and counter in a class:
Example:
public class CallbackCounter
{
protected Int32 Counter { get; set; }
public Int32 MaxCount { get; set; }
public Action Action { get; set; }
public event EventHandler FinalCallback;
public CallbackCounter(Action action, Int32 maxCount)
{
Action = action;
Counter = 0;
MaxCount = maxCount;
}
public void Callback()
{
Action();
Counter++;
if (Counter >= MaxCount)
RaiseFinalCallback();
}
private void RaiseFinalCallback()
{
EventHandler temp = FinalCallback;
if (temp != null)
{
temp(this, EventArgs.Empty);
}
}
}
Use it like following:
CallbackCounter cc = new CallbackCounter(singleCallback, 5);
cc.FinalCallback += (sender, e) => {
// Final callback
};
for (int i = 0; i < 5; i++)
requestSomething(cc.Callback);
Here's a simple program which demonstrates how you can use the Task Parallel Library to call your asynchronous functions and waiting for all to finish to continue. You could then adapt your code to do the same.
class Program
{
static void Main(string[] args)
{
var asyncFunc = new Action<int>(i =>
{
Thread.Sleep((i+1) * 1000);
Console.WriteLine("Called {0}!", i);
});
var callback = new Action(() => Console.WriteLine("Callback called"));
var requests = Enumerable.Range(0, 5)
.Select(i =>
{
return Task.Factory
// wrap asynchronous call in a task
.FromAsync(asyncFunc.BeginInvoke, asyncFunc.EndInvoke, i, asyncFunc)
// register callback
.ContinueWith(_ => callback());
})
.ToArray();
Task.WaitAll(requests);
// do callback
Console.WriteLine("All called!");
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
Console.WriteLine();
}
}
Without seeing how your asynchronous function is implemented, I can only assume you need to change it to return the asynchronous call as a task in order to make this work. Probably something like this would work for you:
Task requestSomething(Action callback)
{
// do stuff...
return Task.Factory
.FromAsync(obj.BeginInvoke,
obj.EndInvoke,
..., // async func arguments
obj)
.ContinueWith(_ => callback());
}
// usage:
var tasks = Enumerable.Range(0, 5)
.Select(_ => requestSomething(singleCallback))
.ToArray();
Task.WaitAll(tasks);
mainCallback();
I think you are going to have to use a thread safe count (ie. use LOCK) which you increment at callback then check the value at the entry point of your callback method to ensure the expected number of methods have completed.
精彩评论