Threading With Parameters

The advantage of threading is the ability to create applications that use more than one thread of execution. For example, a process can have a user interface thread that manages interactions with the user and worker threads that perform other tasks while the user interface thread waits for user input.-MSDN

We have multiple ways to create applications that use more than one thread of execution.

  1. Thread
  2. ThreadPool
  3. Task
  4. Async delegates
  5. Async and wait


Side NOTE

Multi-threading using Thread Class is the most basic level approach to Threading. This gives the maximum control over the thread. You can set priority or check status but at the same time it is costly to create a thread. When It comes to deciding between threadpool and Thread, if you have a long running task, go for Thread Class. Use Threadpool for short tasks where the caller does not need results.

TASK

Finally, the Task class from the Task Parallel Library offers the best of both worlds. Like the ThreadPool, a task does not create its own OS thread. Instead, tasks are executed by aTaskScheduler; the default scheduler simply runs on the ThreadPool.

Unlike the ThreadPool, Task also allows you to find out when it finishes, and (via the generic Task<T>) to return a result. You can call ContinueWith() on an existing Task to make it run more code once the task finishes (if it’s already finished, it will run the callback immediately). If the task is generic, ContinueWith() will pass you the task’s result, allowing you to run more code that uses it.

You can also synchronously wait for a task to finish by calling Wait() (or, for a generic task, by getting the Result property). Like Thread.Join(), this will block the calling thread until the task finishes. Synchronously waiting for a task is usually bad idea; it prevents the calling thread from doing any other work, and can also lead to deadlocks if the task ends up waiting (even asynchronously) for the current thread.

Since tasks still run on the ThreadPool, they should not be used for long-running operations, since they can still fill up the thread pool and block new work. Instead, Task provides a LongRunning option, which will tell the TaskScheduler to spin up a new thread rather than running on the ThreadPool.

All newer high-level concurrency APIs, including the Parallel.For*() methods, PLINQ, C# 5 await, and modern async methods in the BCL, are all built on Task.

Practical Explanation

You can find many articles that use anonymous method to start a thread if you want to use parameter in your method. Here is the one without anonymous or lambda (to clear concepts).

But first I will show Threading concept using Action delegates (i.e. not expecting a return value).

Threading using Action Delegate (No return expected)
  1. using System;  
  2. using System.Threading.Tasks;  
  3. public class Example {  
  4.     private static void printMessage() {  
  5.         int ctr = 0;  
  6.         for (ctr = 0; ctr <= 1000000; ctr++) {}  
  7.         Console.WriteLine("Finished {0} loop iterations", ctr);  
  8.     }  
  9.     public static void Main() {  
  10.         Task t = Task.Factory.StartNew(new Action(printMessage));  
  11.         t.Wait();  
  12.         Console.WriteLine("Next part of program");  
  13.         Console.ReadLine();  
  14.     }  
  15. }  
Threading using Func Delegate (with return expected and input parameters)
  1. using System;  
  2. using System.Threading.Tasks;  
  3. public class Example {  
  4.     private static int printMessage(object c) {  
  5.         int ctr = (int) c;  
  6.         for (ctr = 0; ctr <= 1000000; ctr++) {}  
  7.         return ctr;  
  8.     }  
  9.     public static void Main() {  
  10.         Task < int > t = Task.Factory.StartNew(new Func < object, int > (printMessage), 1);  
  11.         t.Wait();  
  12.         Console.WriteLine("The sum is: " + t.Result);  
  13.         Console.ReadLine();  
  14.     }  
  15. }  

NOTE

There are two ways to use task:

task.run (supported in .Net 4.5) and task.factory.startnew (supported in .net 4).

Action is a delegate (pointer) to a method, that takes zero, one or more input parameters, but does not return anything.

Func is a delegate (pointer) to a method, that takes zero, one or more input parameters, and returns a value (or reference).

Important Link (which I felt)

  • http://dotnetcodr.com/2014/01/01/5-ways-to-start-a-task-in-net-c/

Recommended Reading -asynchronous-delegates-vs-thread-threadpool

  • http://stackoverflow.com/questions/13698129/taskt-vs-asynchronous-delegates-in-c
  • http://stackoverflow.com/questions/1837962/asynchronous-delegates-vs-thread-threadpool
  • http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx
  • http://blog.stephencleary.com/2013/08/startnew-is-dangerous.html