Hello,
I recently stumbled across some Delphi code creating a visualization of the Mandelbrot set (
https://en.wikipedia.org/wiki/Mandelbrot_set).
I wrote this for a math course at my school, back in the days.
After importing it into Lazarus it was still working.
Calculating every pixel of a canvas takes some time so I decided to parallelize the code.
Every point only depends on its indices in the 2d array so multiple threads should not interfere with each other.
Following the documentation about parallel procedures (
https://wiki.freepascal.org/Parallel_procedures) from the wiki I was able to parallelize the code using MTProcs.
However I stumbled across a strange effect:
As soon as I use more than one thread (the number of threads to use can be set by a TEdit field) some pixels get a wrong colour (see attached image).
Rerunning the calculations the number and locations of bad pixels changes.
Using a single thread works fine though, so the basic implementation is right.
Therefore I think it must have to do something with the parallelization.
After trying to find the cause for quite some time now and not succeeding I would like to ask for help.
Can someone please help me and point out what is causing the problem after parallelization?
Thank you very much!
Here is the code:
unit Mandelbrot;
{$IFDEF FPC}
{$MODE Delphi}
{$ENDIF}
interface
uses
{$IFnDEF FPC}
Windows,
{$ELSE}
LCLIntf, LCLType,
{$ENDIF}
SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls,
MTProcs;
type
{ TForm1 }
TForm1 = class(TForm)
PaintBox1: TPaintBox;
Edit3: TEdit;
Button1: TButton;
Panel1: TPanel;
Edit1: TEdit;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
implementation
{$IFnDEF FPC}
{$R *.dfm}
{$ELSE}
{$R *.lfm}
{$ENDIF}
function RGB2TColor(const R, G, B: byte): integer;
begin
Result := R + G shl 8 + B shl 16;
end;
procedure ColourSinglePixel(Index: PtrInt; Data: Pointer; Item: TMultiThreadProcItem);
var
x, y, xx, yy, c, c1, c2: double;
z, i, j, k: integer;
myColor: TColor;
r, g, b: byte;
begin
c := PDouble(Data)^;
z := 0;
{ convert index into x,y coordinates of the canvas }
i := ((Index - 1) div Form1.PaintBox1.Height) + 1;
j := ((Index - 1) mod Form1.PaintBox1.Height) + 1;
x := i / Form1.PaintBox1.Width;
y := j / Form1.PaintBox1.Height;
c1 := c * x;
c2 := c * y;
k := -1;
while (z < 65536) and (x < 4) and (y < 4) do
begin
xx := x * x - y * y + c1;
yy := 2 * y * x + c2;
x := xx;
y := yy;
z := z + 1;
end;
if z >= 256 then
begin
k := z div 256;
r := z div (k + 10);
g := z div (k + 15);
b := z div (k + 20);
end
else
begin
r := z div 2;
g := z div 3 + a div 2;
b := z div 5 + b div 3;
end;
myColor := RGB2TColor(r, g, b);
Form1.PaintBox1.Canvas.Pixels[i, j] := myColor;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
c: double;
pc: PDouble;
begin
c := StrToFloat(Edit3.Text);
pc := @c;
ProcThreadPool.MaxThreadCount := StrToInt(Edit1.Text);
ProcThreadPool.DoParallel(@ColourSinglePixel, 1, PaintBox1.Height * PaintBox1.Width, pc);
end;
end.