Quote Originally Posted by User137 View Post
Problem is in that each thread will access to same particle data at the same time.
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).

Quote Originally Posted by User137 View Post
I could do the "// Move particles" part in main thread after the forces are updated, cause i think that's the fastest part of it. I would also put main thread waiting for those to finish before continuing.
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:
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;
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.
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.