Задача с уведомлением о событии - .net 4 - PullRequest
5 голосов
/ 04 сентября 2011

Вчера на SO я видел поток, спрашивающий код, который кое-что делает таким образом.Я имею в виду, что вы (поток менеджера) запускаете количество задач с помощью API-интерфейсов TPL, и как только они завершают работу, этот поток должен уведомить вас (менеджера) о том, кто поддерживает пул задач.

Так вот код, который я попробовал.Хотя я должен сказать, что это работает так, как я описал выше.

class TaskJob
{
    public delegate void NotificationDelegate(int? taskId,string message);
    public event NotificationDelegate NotifyCompletion;

    public void TaskToRun()
    {
        try
        {
            if (Task.CurrentId == 4)//If its a 4th thread, simulate exception
                throw new Exception();

            Console.WriteLine("Task started with thread id " + Task.CurrentId);
            Thread.Sleep(100000);

            Console.WriteLine("Task finished with thread id " + Task.CurrentId);

            NotifyCompletion(Task.CurrentId, "Successfully completed");
        }
        catch
        {
            NotifyCompletion(Task.CurrentId, "Faulted error");
        }
    }        
}

class Program
{
    static List<Task> taskList = new List<Task>();
    public static void Main()
    {
        for (int i = 0; i < 5; i++)//starting 5 threads/tasks
        {
            TaskJob tb = new TaskJob();
            tb.NotifyCompletion += new ConsoleApplication1.TaskJob.NotificationDelegate(tb_NotifyCompletion);
            Task t = Task.Factory.StartNew(tb.TaskToRun);
            taskList.Add(t);
        }

        Task.WaitAll(taskList.ToArray());
        CheckAndDispose();

        Console.ReadLine();

    }

    private static void CheckAndDispose()
    {
        foreach (var item in taskList)
        {
            Console.WriteLine("Status of task = " + item.Id + " is = " + item.Status);
            item.Dispose();
        }
    }

    static void tb_NotifyCompletion(int? taskId, string message)
    {
        Console.WriteLine("Task with id completed ="+ taskId + " with message = " + message);            
    }
}

Пара голов:

  1. Не беспокойтесь о том, чтобы не поддерживать Task [] вместо того, чтобы иметь список и затем конвертироватьдля массива.Это просто код.Не то чтобы я концентрировался на эффективности.
  2. На данный момент я не беспокоюсь о собственной реализации Dispose.

Теперь я задаю себе пару вопросов, но не могу убедить себя с помощьюподходящий ответ.Вот они:

  1. Хороший ли способ решения проблемы?Или есть лучший способ сделать это?Код, пожалуйста:)
  2. Как убедиться, что объекты задач действительно удаляются (после вызова Dispose), но не реализуют пользовательский шаблон Dispose.
  3. Не проводилось никакого теста утечки памяти с использованием инструментов.Но только визуально ради, вы видите утечки?
  4. В цикле for (основной метод) я создаю объекты класса TaskJob, которые являются локальными для цикла.Таким образом, эти объекты получают gc'd (скажем, вне области видимости) после завершения цикла.Итак, как вызывается событие, которое я подключаю с помощью этого объекта, но оно было удалено после цикла, когда на самом деле происходит событие.
  5. Что-нибудь еще, что вы хотите добавить?

Большое спасибо:)

Ответы [ 2 ]

22 голосов
/ 04 сентября 2011

Нет необходимости делать это самостоятельно - используйте продолжения с Task.ContinueWith или Task<T>.ContinueWith. Это в основном позволяет вам сказать, что делать после завершения задачи, включая выполнение другого кода при сбое, отмене и успешном выполнении.

Также возвращает задание, поэтому вы можете продолжить, когда оно будет выполнено и т. Д.

О, и вы можете дать ему TaskScheduler, чтобы из потока пользовательского интерфейса можно было сказать: «Когда эта фоновая задача завершится, выполните данный делегат в потоке пользовательского интерфейса» или подобные вещи.

Это подход, на котором построены асинхронные методы C # 5.

4 голосов
/ 04 сентября 2011

В качестве альтернативы вы можете попробовать использовать шаблон async / await.Если вы ожидаете Задачу, это означает, что компилятор автоматически сгенерирует ContinueWith для вас.

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

Проверьте мой пост

http://www.codeproject.com/KB/cs/async.aspx

Rx onдругая рука может представлять ваш поток данных, я имею в виду, что вы можете подключить последовательность заданий и подписать свою наблюдаемую на Observer.

http://msdn.microsoft.com/en-us/data/gg577609

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