Hassan Hashemi`s blog

Afghan software developers

Asynchronous and Parallel Programming .Net framework (Part 2)

So far in part one of these series which can be found here we have explored some of the core concepts about Processes, Threads and a little bit about memory management in windows.

In part 2: We will start by categorizing operations that are typical jobs of a separate thread. 

generally speaking about threading will automatically move our mind into two kinds of operations where multi thrading can help us accomplish them more efficiently:

1- I/O Bound operation:

is an operation that spends most of its time waiting for some input and output, such as a simple Console.ReadLine which waits for user to input a value or waiting for a string to be downloaded from the web such as WebClient.DownloadString.

2- Compute bound operation:

or a CPU bound operation is simply a task that its time for being completed is highly dependent to the CPU speed.

these two kind of operation have introduced developers to new problems, when performing these tasks:


Problems raised by I/O bound and Compute Bound operations:

1- keeping user interface responsive.

When a thread is blocked it is simply blocked! if it has been responsible for user interface drawing it will not do that and it will end up with some thing like an application hang for end user. To make it more familiar to you lets create an app that hangs out.
this is going to be a simple WPF window, as you mouse over the window the Background color of window and button will change randomly but once the button is clicked following will happen:
a) color changing is stopped and window cant be moved, resized, etc... .
b) if you go into task manager and see the status of out app it is simple "Not responding".


this is the code for this sample app:

 public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void HangButton_Click(object sender, RoutedEventArgs e)
        {
            /// Simulating long time running I/O operation, this is the ciritical part where this             /// thread balcks off
            /// it will stop repainting UI and responding to OS, after 10 seconds the thread will             /// wake up and continue responding to UI.
            Thread.Sleep(10000);
        }

        private void Window_MouseMove(object sender, MouseEventArgs e)
        {
            ///Handle mouse move event and randomly change background color
            ChangeBackGroundColorRandomly();
        }

        /// <summary>
      /// gets colors from Brushes class, and randomly change background colors of grid and button
        /// </summary>
        private void ChangeBackGroundColorRandomly()
        {
            var colors = new List<Brush>();

            foreach (var item in
                typeof(Brushes).
                GetProperties(BindingFlags.Public | BindingFlags.Static))
            {
                colors.Add((Brush)item.GetValue(null));
            }

            this.HangButton.Background = colors[new Random().Next(1, colors.Count)];
            this.MainGrid.Background = colors[new Random().Next(1, colors.Count)];
        }
    }

in this app we failed to keep the UI Responsive!


2) low Performance.

Another use case for multi-threading is performance which has always been a concern in computer science, one other advantage of multi-threading is increasing performance. You can divide the whole operation into pieces and execute them in parallel.


The problem in previous WPF application can be solved by spinning up a new thread and making it responsible for executing the PerformLongRunning method thus the main will stay responsive to Windows messages and the user interface.


Concept of Parallel programming and Asynchronous programming.

There are differences between these two which i`ll clarify them in next few lines:

Asynchronous Programmingtypically the goal here is to keep system resources busy (not idle waiting for some operation) and keep the user interface responsive.
Parallel Programming: the main purpose of multi-threading in this one is to minimize the latency of the operation and finish it as fastest as possible.
first of all lets break the Async programming:
Asynchrony in the general meaning, is the state of not being synchronized.

Lets get more familiar with it by forgetting about words and have a look at a problem with an example:

Many times we need to access files, web services etc, as you know these operations are not CPU bound but because of the nature of I/O they are time consuming. Another bad news is that while we are waiting for the result of that I/O our program`s execution is stopped and even worse all system resources are idle waiting for that particular operation to complete.

We can fix it by starting a worker thread to perform long time running operation and have the main thread focusing on some thing else such as user interface, windows message loop, etc.. .

in this module we will focus on parallel programming since its easier to learn than Async programming.


What .Net framework gives us on this topic?

there are many ways to simply start a thread in .net framework 4.5 but the purpose of this post is to introduce methods that are documented with standard programming models.

a brief list of available approaches are:

1- Thread class

2- Async deletegate invocation 

3- Event-based Async pattern (using BackGroundworker class btw)

4- ThreadPool.QueueUserWorkItem

5- Task Parallel library (TPL for short)



before we start i want to tell about minimum requirements a Framework such as .net should provide for multi threading.

we need to be able to cancel the progress of a thread any time we wanted.

and of course we need to return result of a thread`s execution if there is any.

in addition to those a good framework should give us a good debugging experience.

dose not matter witch way we are going to use, these tasks has to be done. the only difference is that each framework handles these tasks in different way and thus there is good implementation or modern and also legacy ones. we will explore all of these tasks for each item step by step.

the 5th approach (TPL) is the last effort of Microsoft in order to make developer`s life easier in async and parallel programming. it allows us to write much cleaner and straight forward code. any way, learning some of the old methods are really useful so lets have a brief look at first approach, the Thread class in System.Threading namespace.


Thread class

first step to use Thread class is initialization, this is pretty simple. you new up a Thread instance and pass it the method that you want to be executed on a different thread. the constructor takes a delegate parameter of type ThreadStart. if you navigate to definition of this delegate you are gonna see:

public delegate void ThreadStart();

you might say hey! wait! what if i wanted to pass it a parameter to the thread?

and the answer is that the Thread class has another Constructor that takes an instance of ParameterizedThreadStart delegate, this delegate takes a parameter of type object, the definition for this one is this:

public delegate void ParameterizedThreadStart(object obj);

So to complete first step after passing the delegate instance to constructor of Thread class. There are a couple of other stuff to setup. the most important one is the IsBackGround property of the thread.

If IsBackGround property of a child thread is set to true the thread is considered as a background thread and thus once the main thread is done or exited the process is killed automatically but if it is set to false, CLR will keep the child thread alive and let it run to the end no matter if main thread is done executing or no.

Remember that just instantiating a thread dose not make it execute actually you need to call the Start method on it this will give us a chance to configure it.

so here is complete code for step 1:

 static void Main(string[] args)
        {
            Thread printerThread = new Thread(new ParameterizedThreadStart(Print))
            {
                // always name threads, this will make it easier for us
                // while debugging using visual studio threads window
                Name = "Printer thread",
                IsBackground = false
            };

            printerThread.Start("Hello world");
        }

        private static void Print(object value)
        {
            Console.WriteLine(String.Concat(value, " on thread with id of: ", Thread.CurrentThread.ManagedThreadId));
        }
 

the ManagedThreadId is the unique identifier of each managed thread in clr.

if you do not want to pass it any arguments simply use other overload and pass a ThreadStart delegate to it.

for now we have done initialization and basic starting a thread.

Loading