Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Task with event notification - .net 4

Yesterday on SO, i saw a thread asking for a code which some what does this way. I mean, you (manager thread) start number of tasks using TPL APIs and once they are completed job, that thread should notify you (Manager) back who maintains Task pool.

So here is the code which i tried. Although i must say it works as i describe above.

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

Couple of heads up:

  1. Dont worry about not maintaining Task[] rather than having a list and then converting to array. Its just a code. Not that i am concentrating on efficiency.
  2. Am not worried on custom Dispose implementation as of now.

Now i am asking myself couple of questions, but fail to convince myself with an suitable answer. Here are they:

  1. Is this way solving the problem good? Or is there a better way to do it? Code please :)
  2. How to make sure that the tasks objects are really disposed (upon calling Dispose) but not implementing the custom Dispose pattern.
  3. Have not done any memory leak test using tools. But just visual sake, do you see leaks?
  4. In the for loop (main method) i am creating TaskJob class objects which are local to loop. Thus these objects gets gc'd (lets say out of scope) after loop completion. So, how the event is fired back which i am hooking up using this object but it has been disposed after loop when actually the event is fired.
  5. Any thing else you wish to add?

Thanks alot :)

like image 328
Zenwalker Avatar asked Sep 04 '11 05:09

Zenwalker


2 Answers

There's no need to do this yourself at all - use continuations with Task.ContinueWith or Task<T>.ContinueWith. That basically lets you say what to do when a task completes - including executing different code on failure, cancellation, and success.

It also returns a task, so you can then continue when that's completed etc.

Oh, and you can give it a TaskScheduler, so that from a UI thread you can say, "When this background task finishes, execute the given delegate on the UI thread" or similar things.

This is the approach that C# 5 async methods are built on.

like image 65
Jon Skeet Avatar answered Oct 08 '22 01:10

Jon Skeet


Alternatively you can try using async / await pattern. If you await a Task that means the compiler will automatically generate the ContinueWith for you.

If you use this pattern you can write normal async methods which will itself generate State machine.

Check my post

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

Rx on the other hand can represent your data flow, I mean you can hook a sequence of jobs and subscribe your observable on an Observer.

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

like image 26
abhishek Avatar answered Oct 08 '22 01:10

abhishek