Hallo,
ich wollte meinen kleinen Fraktal-Visualisierer auf Threads umstellen, um meinen DualCore nutzen zu können. Das Programm erstellt eine Reihe von Bitmaps, die man dann zu einem Video konvertieren kann. Am Ende hat mein ein Video, das in das Mandelbrot Fraktal hineinzoomt.
Ich habe mich an das Tutorial "Threads mit Delphi" von Luckie gehalten, aber schon bei einem Thread gibt es große Schwierigkeiten. Folgendes ist mir schon untergekommen (ohne, dass ich zwischendurch das Programm neu kompiliert oder etwas im Code geändert habe):
• Das Bild steht still, keine Zoombewegung
• Das Bild wird nur am linken Rand etwas bemalt, der Rest bleibt weiß
• Es gibt eine
Exception "Ungültiges
Handle", was sich auf das Thread
Handle bezieht
• Es läuft alles ganz normal
Diese Dinge treten meißtens irgendwann während der Berechnung auf (jedoch relativ schnell, nach einigen Dutzend Frames), können aber auch mal beim ersten Durchlauf erscheinen.
Ich muss viele Parameter an den Thread übergeben, habe es aber wie im Tutorial beschrieben gemacht. Am besten zeige ich mal den betreffenden Code:
Delphi-Quellcode:
type
TThreadParams = packed record
public
Center_x, Center_y, Range_x, Range_y, dx, dy, MaxValue: extended;
MaxIterations, Counter: integer;
Bitmap: TBitmap;
end;
PThreadParams = ^TThreadParams;
//[...]
procedure TMandelbrotSet.SaveSetZoom;
var
counter: integer;
dx, dy: extended;
Parameter: TThreadParams;
Thread: THandle;
ThreadID: Cardinal;
Bitmap: TBitmap;
begin
// Parameter initialisieren
counter:=1;
Bitmap:=TBitmap.Create;
Bitmap.Width:=x; // Konstante
Bitmap.Height:=y; // Konstante
Range_x:=4;
Range_y:=3;
dx:=Range_x / x;
dy:=Range_y / y;
maxIterations:=200;
// Konstante Parameter einmalig setzen (gehören zu TMandelbrotSet (privat) und sind initialisiert)
Parameter.MaxValue:=MaxValue;
Parameter.Center_x:=Center_x;
Parameter.Center_y:=Center_y;
Parameter.Bitmap:=Bitmap;
// Prozesspriorität verringern, um andere Programme nicht zu "stören"
SetPriorityClass(GetCurrentProcess, IDLE_PRIORITY_CLASS);
while (Range_x>0.0000001) do
begin
// Aktuelle Parameter für Thread übernehmen
Parameter.Range_x:=Range_x;
Parameter.Range_y:=Range_y;
Parameter.dx:=dx;
Parameter.dy:=dy;
Parameter.MaxIterations:=MaxIterations;
Parameter.Counter:=Counter;
// Thread erzeugen
Thread := BeginThread(nil, 0, @ThreadFunc, @Parameter, CREATE_SUSPENDED, ThreadID);
// Threadpriorität und gewünschten Prozessor setzen
SetThreadPriority(Thread, THREAD_PRIORITY_IDLE);
SetThreadIdealProcessor(Thread, 0);
// Thread starten
ResumeThread(Thread);
// Parameter für nächsten Frame setzen:
Range_x:=Range_x*0.95;
Range_y:=Range_y*0.95;
dx:=Range_x / x;
dy:=Range_y / y;
maxIterations:=round(200+(Counter*1.2));
Inc(Counter);
Application.ProcessMessages;
// Auf Thread warten
WaitForSingleObject(Thread, INFINITE);
CloseHandle(Thread);
end;
Bitmap.Free;
// Priorität auf Standard zurücksetzen
SetPriorityClass(GetCurrentProcess, NORMAL_PRIORITY_CLASS);
end;
und die ThreadFunc:
Delphi-Quellcode:
function ThreadFunc(Params: PThreadParams): Cardinal;
var
fBitmap: TBitmap;
fMaxIterations, fIterations, fAverage, fPxl_x,
fPxl_y, fi, fj, fcounter: integer;
fx0, fx1, fy1, fCenter_x, fCenter_y, fRange_x, fRange_y,
fRealC, fImagC, fMaxValue, fdx, fdy: extended;
fr, fg,
fb, ffulls: byte;
begin
// Parameter auslesen
fBitmap:=PThreadParams(Params)^.Bitmap;
fdx:=PThreadParams(Params)^.dx;
fdy:=PThreadParams(Params)^.dy;
fCenter_x:=PThreadParams(Params)^.Center_x;
fCenter_y:=PThreadParams(Params)^.Center_y;
fRange_x:=PThreadParams(Params)^.Range_x;
fRange_y:=PThreadParams(Params)^.Range_y;
fMaxIterations:=PThreadParams(Params)^.MaxIterations;
fMaxValue:=PThreadParams(Params)^.MaxValue;
fCounter:=PThreadParams(Params)^.Counter;
// Berechnung [...]
Result:=0;
end;
Die Berechnung an sich habe ich nicht verändert. Sie hat vorher immer ohne Probleme funktioniert und daher gehe ich vorerst davon aus, dass es an den Parametern liegt.
Ich freue mich über Ratschläge!