This is my first post. I published it in Italian and many people asked me to traslate it in English so here the english version.
The parallel computing is more and more, within the reach of common programming languages. Programs or routines that are simple processing cycles (using for and foreach construct), that may exist and coexist independently, can be easily managed with parallel computing.
Given my difficulty to buy third-party products, first because it requires you to learn the logic, which may also not be acceptable, and secondly because I have an innate desire to discover the "hot water", I have decided to study the basics of Multithreading in C#.
The C# language it is well provided and enables intelligent solutions in this sense. The article assumes that the reader should have the basics of object-oriented programming and knowledge of the delegation mechanism as well as Threads theory.
I was in fact in the unfortunate situation of having to increase the computing performance of a written application by a third party in C#. The computational routines in question were sequential, nested loops but potentially independents. I immediately thought of a class that would manage these cycles, breaking them up into n-parts depending on the number of processors, and that at the same time enabling it to manage the execution status.
The solution have required: firstly, the definition of a class, the adaptation of calculation code. In this article I will explain up the wrapper class, called MPBox (Multi-Processor Box), it is a basic project to evolve into more complex cases, but still a good starting point.
Initial Specifications
The class needs to manage:
- The list of parameters of the calculation procedures (eg. myproc (a, b, c, ...)).
- The start up and the procedures status (eg, each is a thread).
- The termination event and a "State" property.
Different Parameters
Manage different parameters in types and values is a big problem that I solved concentrating these in "ad hoc" classes derived from a simple basic class:
public class MyParamsItem { public int min = 0; public int max = 0; public string caption = ""; public MyParamsItem(int Min, int Max, string Caption) { min = Min; max = Max; caption = Caption; } }In practice, if the procedure myproc (a, b, c) admits the parameters a, b, c, these will be integrated into a derived object MyCustomParamsItem which exhibits the following properties a, b, c, min, max, and caption. The procedure definition should be modified in myproc (MyCustomParamsItem obj), this is the first step to abstract the calculation procedures. I hope to be more clear in the next explanations.
Different Parameters and MyParamsItem Class
Execution of Procedures
Using the .NET delegation system, it is possible to have a procedure reference as parameter, thats cool! And to store this reference somewhere. Amazing!
The wrapper class called MPBox exposes a method for append these procedure references and the parameters used by these procedures:
public void Add(MyProc apProc, MyParamsItem aoParamsItem)
Here how the procedure has to be defined:
public delegate void MyProc(MyParamsItem aoParamsItem);
once appended this procedure and theirs parameters (the parameters defines also the cicle with the min and max), you are ready to start the Threads. The .NET Threading system will manage every thread in a asynchronous way assigning each one to a specific processor.
public void Start()
I try to repeat the steps:
1. Modify the procedure in order to receive one standard parameter object, derived from MyParamsItem. This object will contain the range of loop (min, max) and the other used parameters.
2. Append in a special Box (MPBox object) all cycles identified by: a standard Procedure and a specific Parameter item object.
For example if I have a procedure with a cicle for i = 0 to 100, and a computer with 5 processors, I can image to split this procedure into 5 new calls. Each call can identify a standard procedure, for i = min to max, where min and max change in every loop.
loop 1) 1..20
loop 2) 21..40
loop 3) 41..60
loop 4) 61..80
loop 5) 81..100
Start Thread: MPBox.Start()
Finish
While Thread are working a boolean variable "Working" is True.
while (mp.Working) { System.Threading.Thread.Sleep(10); }
At the end of all Threads, the object fires an event:
public event ThreadCustomEvent OnFinish; public delegate void ThreadCustomEvent(object sender, System.EventArgs e);
The Example
The example (download here) allows to set a cicle min, max. This cicle at the Start(), will use a single processor, then two, again three, etc. until n. The results at video, will show the used times.
Every idea to improve this class will be well accepted.