Unles your threads are only reading the data and not changing it there should be no problem. Problem would only ocur if one of the threads would be changing some values of one particle while other tread would be reading it (data corruption).
First of all never and I mean NEVER put the min thread on hold for other threads to finish. Why? Doing so you prevent your application to process Windows messages or System messages if you are using some other platform. And if you do so then your application would be considered as being hanged application by the OS and your OS might simply go and forcefully kill it. You definitly don't want this.
If you use double-buffering approach you actually dont even need main thread to do any moving.
Let me try to explain you how would I approach to this problem:
First I would save information for each particle in class object with double-buffering so I that I have acces to the variables using properties. Why using properties?
Becouse with getter and setter methods of properties you can easily implement double-buffering.
The class code for particle wouls look something like this:
As you see each class has two internal variables for every property (value) that might be changed by other threads during curent cycle while still preserving acces to current data without it being corupted by other threads.Code:type TParticle = class(TObject) private PSecondBuffer: ^Boolean; FPosition1: T3DPoint; FPosition2: T3DPoint; FForce1: T3DVector; FForce2: T3DVector; protected function GetPosition: T3DPosition; procedure SetPosition(AValue: T3DPoint); function GetForce: T3DVector; procedure SetForce (AValue: T3DVector); public constructor Create(AOwner: TObject; var SecondBuffer: Boolean); override; property Position: T3DPoint read GetPosition write SetPosition; property Force: T3DVector read GetForce write SetForce; end; //We use this global variable to determine whether we will read from primary or secondary buffer var SecondBuffer: Boolean; implementation { TParticle } constructor TParticle.Create(AOwner: TObject; var SecondBuffer: Boolean); begin inherited; //We assing pointer to external boalean variable for controling whether //we read from primary or secondary buffer FSecondBuffer := @SecondBuffer; end; function TParticle.GetForce: T3DVector; begin //If the second buffer is true then we read from second force variable //else we read from first force variable if FSecondBuffer = True then Result := FForce2 //Secondarry buffer else Result := FForce1; //Primary buffer end; function TParticle.GetPosition: T3DPosition; begin //If the second buffer is true then we read from second postiion variable //else we read from first position variable if FSecondBuffer = True then Result := FPosition2 //Secondarry buffer else Result := FPosition1; //Primary buffer end; procedure TParticle.SetForce(AValue: T3DVector); begin //With the difference of getter methods we now if second buffer is true //write data to first force variable to avoid changing the data that might //be read by other threads //We never change the same variable as it is available for reading if FSecondBuffer = True then FForce1 := AValue //Primary buffer esle FForce2 := AValue; //Secondarry buffer end; procedure TParticle.SetPosition(AValue: T3DPoint); begin //We handle position variable changing same as above. if FSecondBuffer = ture then FPosition1 := AValue //Primary buffer else FPosition2 := AValue; //Secondarry buffer end;
For contgrolling this we are actually using external boolean variable. This means that with a single call we can change, which internal variable would be used for reading and which for writing, for even a few thousands of class objects if we need it. This is probably the best solution for controlling class double-buffering.
NOTE1: If you need per class double-bufering control you need as many global variables as you have distict classes.
NOTE2: You could also save this information into the class itself but then you will have to update this information fora each class which could result in several thousands calls.
Bookmarks