Выполнить обратный вызов, когда несколько асинхронных операций завершены - PullRequest
0 голосов
/ 04 января 2011

У меня есть асинхронная функция, которая принимает обратный вызов

void requestSomething (Action callback)

Мне нужно запустить ее несколько раз и запустить MainCallback после завершения всех функций

for (int i=0;i<5;i++)
   requestSomething (singleCallback);

Я представляю, как это сделать с помощью счетчика, который считает 5 раз, а затем запускает mainCallback, но я считаю, что есть лучший способ сделать это.

edit:

Я могу сделать это следующим образом:

int counter = 5;

for (int i=0;i<counter;i++)
{
       requestSomething (()=> { counter--;
                                  if (counter == 0)
                                     mainCallback()} );
}

Есть ли лучший способ реализовать эту логику?

Ответы [ 3 ]

1 голос
/ 04 января 2011

Вот простая программа, которая демонстрирует, как вы можете использовать Task Parallel Library для вызова ваших асинхронных функций и ожидания завершения всех. Затем вы можете адаптировать свой код, чтобы сделать то же самое.

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();
    }
}

Не видя, как реализована ваша асинхронная функция, я могу только предположить, что вам нужно изменить ее, чтобы она возвращала асинхронный вызов как задачу, чтобы эта работа работала. Возможно, что-то вроде этого будет работать для вас:

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();
1 голос
/ 04 января 2011

Вы можете инкапсулировать обратный вызов и счетчик в классе:

Пример:

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);
        }
    }
} 

Используйте его следующим образом:

CallbackCounter cc = new CallbackCounter(singleCallback, 5);

cc.FinalCallback += (sender, e) => { 
    // Final callback
};

for (int i = 0; i < 5; i++)
    requestSomething(cc.Callback);
0 голосов
/ 04 января 2011

Я думаю, вам придется использовать потокобезопасный счетчик (т. Е. Использовать LOCK), который вы увеличиваете при обратном вызове, а затем проверяете значение в точке входа вашего метода обратного вызова, чтобы убедиться, что ожидаемое количество методов завершено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...