Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / programming / threads

The five minute guide to Parallel Programming in c#.

4.69/5 (6 votes)
22 Jan 2014CPOL4 min read 29K  
Working introduction to Parallel Programming

Objective 

This tip is a quick "get up and running" introduction to parallel programming using a working example rather than any theory.

Example Origin 


When I adopted the message handler approach to distributing ticket data between busses and their control office, my initial instinct was that this tailor made for a parallel solution with each datastore on its own thread. It quickly occured to me that this was a sure and certain way to corrupt my database. e.g  the row to record a ticket validation could be created before the row to record the sale of the same ticket if its thread got priority!

However as time moved on a scenario has evolved that is ideally suited to parallel programming. When a customer with a series of unpaid tickets makes a payment to cover the outstanding amount, this payment is initially recorded in sequence with any other associated data, e.g. a preceeding sale. Then I need to kick off a task which writes a contra entry to the account for the funds of the to be redistributed, and scans the purchase list for that customer beginning with the oldest unpaid ticket and writes an entry to pay each off until either the funds are used up or that customer has no more tickets with money owed on them. There is no technical database dependency on this task, and if run sequentially could present a performance bottleneck.

 

Using the Sample Code

I used Listing 2-4 of Adam Freeman's book "Pro .NET 4 Parallel Programming in C# as my template.

I started with a standard C# console application, and included the System.Threading namespace. I renamed the application's autogenerated class from "Program" to "ParallelTest". Then I added a static integer method, "Timed_Message" to take a  message string and an interval as arguments. This method loops 10 times and sends text to the console at intervals based on the interval argument supplied.

The main method spawns two tasks each calling "Timed_Message", but supplying different text and interval values for each instance. There is a final Console.Readline to prevent the main thread from concluding and killing off the sub threads before they get the opportunity to show how they work together. This is the code:

<pre>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace ParallelTest
{
    class ParallelTest
    {
        private static int Timed_Message(String arg_Message, int arg_Interval)
        {
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("Source {0} - Cycle {1} for Interval {2}", arg_Message, i, arg_Interval);
                Thread.Sleep(1000 * arg_Interval);
            }

            Console.WriteLine("{0} - Complete", arg_Message);
            return 0;
        }

        static void Main(string[] args)
        {
            int RetCode = 0;
            Task RedistributionTask = new Task(() => RetCode = Timed_Message("Five ", 4));
            RedistributionTask.Start();
            Task AltRedistributionTask = new Task(() => RetCode = Timed_Message("Three ", 2));
            AltRedistributionTask.Start();
            //Timed_Message("Main", 6);

            // wait for input before exiting
            Console.WriteLine("Press enter to finish after both [Complete] messages appear.");
            Console.ReadLine();
        }

    }
}
</pre>

Press enter to finish after both [Complete] messages appear.
Source Five  - Cycle 0 for Interval 4
Source Three  - Cycle 0 for Interval 2
Source Three  - Cycle 1 for Interval 2
Source Five  - Cycle 1 for Interval 4
Source Three  - Cycle 2 for Interval 2
Source Three  - Cycle 3 for Interval 2
Source Five  - Cycle 2 for Interval 4
Source Three  - Cycle 4 for Interval 2
Source Three  - Cycle 5 for Interval 2
Source Five  - Cycle 3 for Interval 4
Source Three  - Cycle 6 for Interval 2
Source Three  - Cycle 7 for Interval 2
Source Five  - Cycle 4 for Interval 4
Source Three  - Cycle 8 for Interval 2
Source Three  - Cycle 9 for Interval 2
Source Five  - Cycle 5 for Interval 4
Three  - Complete
Source Five  - Cycle 6 for Interval 4
Source Five  - Cycle 7 for Interval 4
Source Five  - Cycle 8 for Interval 4
Source Five  - Cycle 9 for Interval 4
Five  - Complete

Try this at home.

Uncomment the line Timed_Message("Main", 6);  in the main method and re run the application. Now you will see the main thread running in parallel with the other two, and because we have used a longer interval, it continues working after the other two are done.  This is an extract from the revised output :

Source Main - Cycle 3 for Interval 6
Source Three  - Cycle 9 for Interval 2
Source Five  - Cycle 5 for Interval 4
Three  - Complete
Source Main - Cycle 4 for Interval 6
Source Five  - Cycle 6 for Interval 4
Source Five  - Cycle 7 for Interval 4
Source Main - Cycle 5 for Interval 6
Source Five  - Cycle 8 for Interval 4
Source Main - Cycle 6 for Interval 6
Source Five  - Cycle 9 for Interval 4
Five  - Complete
Source Main - Cycle 7 for Interval 6
Source Main - Cycle 8 for Interval 6
Source Main - Cycle 9 for Interval 6
Main - Complete
Press enter to finish after both [Complete] messages appear.

History 

22-Jan-2014 1.0 Initial post

22-Jan-2014 1.1 Code reformatted


License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)