Multithreading using Delegates in C#
I've recently been experimenting with C#'s delegates, and here is an example of
how they can be used for multithreading. I've used a ray tracer as a good example
of something that can be multithreaded easily. This ray tracer has been grabbed from LukeH's
awesome LINQ example here:
LukeH's WebLog A Ray Tracer in C# 3.0. I've modified it a bit for my purposes just a little. What i'm trying to accomplish here is getting 4 delegates to render different parts of a scene in simultaneous threads, and stitch them together for one image, and save it to disk.
Firstly, you've got to declare a delegate type. It's a little like creating a new enum, in that you're creating a new variable type. This code goes in the class declaration, outside of any functions. In my case, i'm declaring that my delegate has 2 parameters:
Now i've got my delegate, i want to create my function that fits with the delegate's signature of taking 2 integers:
Okay, now i've got my delegate type and my actual delegate, i want to use them, as i do in my Run function below. Notice that for the 3rd one, i'm using an anonymous delegate for the "Hey: I've finished" callback, for no real reason. The 'CallbackMethod' function is another delegate, matching the signature for the AsyncCallback delegate type.
Here is the entire solution (VS2008): multithreadeddelegatesraytracedemo
Cheers, and thanks for reading.
delegate void RenderSection(int top, int bottom);
/// <summary>
/// This is the delegate that renders a part of the image, a delegate for RenderSection
/// </summary>
public void RenderASection(int top, int bottom)
{
// Raytrace just this section of the scene
Bitmap SectionBitmap = new Bitmap(width, height);
RayTracer rayTracer = new RayTracer(width, height,
(int x, int y, System.Drawing.Color color) =>
{
SectionBitmap.SetPixel(x, y, color);
}
);
rayTracer.Render(rayTracer.DefaultScene, top, bottom);
// Copy my part of the scene into the overall scene
lock (bitmap)
{
Graphics g = Graphics.FromImage(bitmap);
g.DrawImage(
SectionBitmap,
new Rectangle(0, top, width, bottom),
new Rectangle(0, top, width, bottom),
GraphicsUnit.Pixel);
}
}public void Run()
{
width = 800;
height = 800;
bitmap = new Bitmap(width, height);
RenderSection myDelegate = RenderASection;
// Run it with different parameters
IAsyncResult ar1 = myDelegate.BeginInvoke(0, 200, CallbackMethod, null);
IAsyncResult ar2 = myDelegate.BeginInvoke(200, 400, CallbackMethod, null);
IAsyncResult ar3 = myDelegate.BeginInvoke(400, 600,
delegate(IAsyncResult ar)
{ Console.WriteLine("Section finished (anonymous delegate)"); },
null);
IAsyncResult ar4 = myDelegate.BeginInvoke(600, height, CallbackMethod, null);
// Wait for them to finish
myDelegate.EndInvoke(ar1);
myDelegate.EndInvoke(ar2);
myDelegate.EndInvoke(ar3);
myDelegate.EndInvoke(ar4);
// Save the output bitmap
bitmap.Save("RayTrace.png");
}
/// <summary>
/// This is a function we can use as a delegate for AsyncCallback
/// </summary>
void CallbackMethod(IAsyncResult ar)
{
Console.WriteLine("Section finished");
}