I want to get some query from server time by time and list this URL query on the array of records.
For freeing of memory must free the elements of an array that procced. This process is on the thread to prevent freezing of App. If the array is not locked, maybe deleting of element rise exception because that other element is in process or adding or deleting an index of element changed.
My question is: ’How can I lock an array of records for adding and deleting an element in the thread?’
This sample code is simplified for understanding my actual App code:
uses IdHTTP;
type
tMyRecAra=record
sta:integer;
url:string;
// ...
// ...
end;
var MyRecAra: array of tMyRecAra;
procedure TfoTestAra.btAddClick(Sender: TObject);
var cou:integer;
begin
// start lock array MyRecAra ?
cou:=length(MyRecAra);
SetLength(MyRecAra, length(MyRecAra) 1);
MyRecAra[cou].sta:=0;
MyRecAra[cou].url:='http:/......';
//- stop lock array MyRecAra ?
end;
procedure TfoTestAra.btStartClick(Sender: TObject);
var
IdHTTP1:TIdHTTP;
mainThr,curThr : TThread;
cStream:TMemoryStream;
begin
mainThr := TThread.CreateAnonymousThread(
procedure
begin
while true {or other condition} do
begin
curThr := TThread.CreateAnonymousThread(
procedure
var i:integer;
begin
// start lock array MyRecAra ?
for i := 0 to (length(MyRecAra)-1) do
begin
if (MyRecAra[i].sta=0) then
begin
MyRecAra[i].sta:=1;
//...
//..
{for example : IdHTTP1.Get(MyRecAra[i].url,cStream)};
//...
//..
end;
end;
//- stop lock array MyRecAra ?
end);
curThr.Start;
sleep(5000);
end;
end);
mainThr.start;
end;
procedure TfoTestAra.Timer1Timer(Sender: TObject);
var
sumFee:integer;
i, j:integer;
begin
// timer.interval=10000;
// start lock array MyRecAra?
sumFee:=0;
for i := 0 to (length(MyRecAra)-1) do
begin
if (MyRecAra[i].sta=1) then
begin
inc(sumFee);
for j := (i 1) to sumFee-1 do
begin
if (MyRecAra[j].sta <> 1) then
MyRecAra[i]:=MyRecAra[j]
end;
end;
end;
if sumFee<>0 then
SetLength(MyRecAra, (length(MyRecAra)-sumFee));
// stop lock array MyRecAra ?
end;
End.
CodePudding user response:
You can use lock to protect access to shared data and then general pattern in all places where you access the data would be:
Lock.Enter;
try
// procected code
finally
Lock.Leave;
end;
You need to declare lock variable in the same scope as the data that needs protection and you need to initialize that lock before it is used for the first time and free it when it is no longer needed.
For instance, if your MyRecAra
is global data in unit, then Lock
also needs to be global and initialized in initialization section of the unit and released in finalization section.
If MyRecAra
is field in form or some other class, then Lock
would also be a field in that class, initialized in constructor and released in destructor.
Commonly used lock is TCriticalSection
. There are other types of locks, but for start this one will do just fine.
var
Lock: TCriticalSection;
MyRecAra: TMyRecAra;
initialization
Lock := TCriticalSection.Create;
finalization
Lock.Free;
end.