开发者

Run callback when several async operation has finished

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜