Click here to Skip to main content
Click here to Skip to main content

OpenMP style multi-threading in C#

, 17 Sep 2008 CPOL
Rate this:
Please Sign up or sign in to vote.
Simplified multi-threading of for loops in C#, with an interface akin to OpenMP.


This article demonstrates the use of C# anonymous delegates and a using() statement to achieve a very simple interface to multi-threading, in a manner in akin to OpenMP in C++.

It also provides an implementation and example of a multi-threading object, avForThread.


Threading, in any language, introduces problems at all levels, from design, to implementation, to debugging. The OpenMP extension to Visual C++ allows programmers either to quickly parallelise otherwise sequential functions, or at least to test whether more specialised threading routines will be beneficial for their task. Unfortunately, currently, C# has no OpenMP extension implementation (at the time of writing, at least!)

However, C# does have several very elegant toys which can be combined to produce a coding interface very similar to that of OpenMP; primarily anonymous delegates, and using().

Anonymous delegates sport two great properties. One, they can be casually defined within function definitions; two, objects defined outside of the scope of the delegate, but within the defining scope, are still visible and accessible.

For example:

public delegate void testSetter(int setTo); 
void myMethod()
  int b;
  testSetter D = delegate(int setTo) { b= setTo; }


In this case, the delegate instance D is set to an anonymous delegate defined inline. The delegate, in this case, sets b to the value of the incoming parameter.

Whilst this syntax is evidently not useful in this case, it does allow the programmer a large amount of flexibility, especially when it comes to dynamic querying, or polymorphic behaviour without the need for the bloat of new classes.

One use where this syntax is very useful is in being able to wrap up functions with any number of parameters and have threads execute them.

For example, if we pass an anonymous delegate to the constructor of a System.Threading.Thread object, we can then run the delegate with the parameters of our choosing.

So, let's say we want to take a for loop and split it into a number of threads. (In fact, the provided code only handles for loops, but it could be easily extended to handle any sequential mutual calculations within any looping structure - just don't write to data which may be read or written to by another thread!) As we want to use the calculated data immediately, we will wait for the threads to return.

The code attached defines all tasks needed for this kind of operations within one class, avForThread.

To remove the need to call a method to wait for the completion of the threads, we can employ a trick with a using() statement such that the execution will not leave the using block until the threads have returned. This is achieved by the call to the thread wait method, avForThread.WaitToFinish(), stated within avForThread.Dispose().

Using the code

So, we will start by creating a test for loop, the kind of code that could be parallelised...

static void Main(string[] args)
    // we want to call calculateSomething 1M times.
    int dataSize = 1000000;

    // we'll store the data in an array
    int[] data = new int[dataSize];

    // we'll do the same calculation twice,
    // once without thread, and another time with

    // without threading
    for (int i = 0; i < dataSize; i++)
        data[i] = calculateSomething(i);

We'll then move on to performing the same task using the threaded notation, using an avForThread object. We will need to pass the same start and end values used by our simple for loop. We will also pass the number of threads to use, and of course, the parameterised delegate to execute.

     using (new avForThread(0, dataSize, 4,
        delegate(int start, int end)
            for (int i = start; i < end; i++)
                data[i] = calculateSomething(i);
    ) ;

N.B.: To change the looping range, we can modify the 0 or dataSize arguments. Only, we don't need to modify start or end - they will be automatically set per thread by avForThread.

As you can see, the syntax is very simple and flexible. You will need to test with differing numbers of threads to gain the best performance. Depending on the complexity of the task and the CPU, there will be a "sweet spot" where the threaded code is far faster than the non-threaded code. Experiment with numThreads in the range 2 to 20.

For your own implementations, you'll need to keep roughly the same format as the for loop has here. By the way, here, the using() simply forces the runtime to call the Dispose method of the class, which in turn will wait for the threads to finish.

You could also omit the using statement, carry on working, and then call the avForThread.WaitToFinish() method explicitly.

As I said, if you want to go beyond a simple i++ for loop, some simple customisation of avForThread will be required.

Have fun!


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


About the Author

Other Lecturer, Researcher, Software Developer, Animator
United Kingdom United Kingdom
Adam Vanner has worked at the National Centre for Computer Animation at Bournemouth University in the UK since 2000.
Specialising in 3D animation software development, 3D animation productions and motion capture, he has worked on a wide range of projects from design and development of commercial animation software, to collaborating with artists on animation for artworks and theatre.

Comments and Discussions

QuestionGood Information PinmemberAbhishek Nandy24-Oct-12 5:49 
GeneralMSDN implementation of this PinmemberGamingdrake13-Jun-11 17:10 
Questionthread exit before the task complete Pinmembermnansyah15-Sep-09 21:01 
GeneralRestart thread PinmemberRobin25-May-09 23:55 
GeneralMore than one thread Issue (Alert!) PinmemberAram Azhari28-Jan-09 22:58 
GeneralError in code Pinmembermikhmv5-Dec-08 16:02 
GeneralRe: Error in code Pinmemberumzbqsdf15-May-09 6:32 
GeneralThread safety Pinmemberpopart24-Sep-08 22:26 
GeneralRe: Thread safety Pinmemberadamvanner8-Oct-08 14:45 
GeneralRe: Thread safety Pinmemberpopart8-Oct-08 22:06 
Hi Adam, I can conform your words, and besides the small problems - the already pointed out "bug" and something I found - the ranges in the anonymous delegate should be adjusted (<= instead of <) in order to calculate the last element in the range, beside that it's working as expected and there are no locking issues nor there are race conditions. Some other adjustment I've made was to increase the number of milliseconds (100 or more instead of 10) the polling thread sleeps, which proved to have positive performance effect in case you have very large number of calculations (10 -100 Millions), so you make less polls and leave the CPU to the calculating threads, something else was to change the results array type to Unsigned Long in order to have correct arithmetic and check for overflow, also as you suggested I've checked for correctness using single threaded calculation. As you suggested I found the sweet spot for my environment (single core CPU) to be 3 to 5 threads. I can post my code if you have interest. What's more interesting is how would this elegant solution play against the big guys - TPL from .NET world, and also OpenMP, Intel TBB from the "native" world, this is something I would try to test, but I can't commit to concrete time frame for this right now, sorry. Any way your solution is very appealing for simple linear problem solving and from now it becomes part of my tool belt, thank you!
Best Regards, Nikolay Popov
GeneralThe sources contain the bug!!! Pinmemberqweqrsfeg6hdfm5wufd23-Sep-08 4:52 
GeneralRe: The sources contain the bug!!! [modified] Pinmemberadamvanner8-Oct-08 14:35 
QuestionMS Parallel Extensions library PinmemberNick Butler23-Sep-08 0:46 
AnswerRe: MS Parallel Extensions library Pinmemberadamvanner8-Oct-08 14:38 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.1411023.1 | Last Updated 17 Sep 2008
Article Copyright 2008 by adamvanner
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid