如何锁定记录数组以在线程中添加和删除元素

How can lock array of records for adding and deleting element in thread

我想一次又一次地从服务器获取一些查询,并在记录数组中列出这个 URL 查询。

要释放内存,必须释放处理的数组元素。 这个进程在线程上,防止App卡死。 如果数组未锁定,则删除元素可能会引发异常,因为其他元素正在处理中,或者添加或删除元素的索引已更改。

我的问题是:‘如何锁定用于在线程中添加和删除元素的记录数组?’

为了理解我的实际 App 代码,简化了此示例代码:

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.

您可以使用锁来保护对共享数据的访问,然后在您访问数据的所有地方的一般模式是:

Lock.Enter;
try
  // procected code
finally
  Lock.Leave;
end;

您需要在与需要保护的数据相同的范围内声明锁变量,并且您需要在第一次使用之前初始化该锁,并在不再需要时释放它。

比如你的MyRecAra是unit中的全局数据,那么Lock也需要是全局的,在unit的initialization部分初始化,在finalization部分release。

如果 MyRecAra 是表单中的字段或其他 class,那么 Lock 也将是 class 中的字段,在构造函数中初始化并在析构函数中释放.

常用的锁是TCriticalSection。还有其他类型的锁,但作为开始,这个就可以了。

var
  Lock: TCriticalSection;
  MyRecAra: TMyRecAra; 

initialization

  Lock := TCriticalSection.Create;

finalization

  Lock.Free;

end.