0

我有 100 项记录类型的静态数组:

TMy_Array:array[1..100] of T;

其中 T 是:

T = record
  A: double;
  B: Date;
  C: String;
end;

我有n类似的线程在修改它们的元素TMy_Array

TMy_Array[n].A; 
TMy_Array[n].B; 
TMy_Array[n].C)`. 

N接近100

我还有 10 个其他线程可以选择性地修改任何字段TMy_Array。为了安全地实现这一点,我应该使用关键部分,问题来了:

是否只使用一个临界区不会导致争用和等待访问数组的线程过度拥挤?

也许我可以或应该应用 100 个关键部分来保护对 T_Array 中特定项目的访问并且不会阻塞其他线程?

Var
  Cs:array [1..100] of TRTLCriticalSection;

//then for n-thread:
EnterCriticalSection(CS[n]);
TMy_Array[n].A:=…;
TMy_Array[n].B:=…;
TMy_Array[n].C:=…;
LeaveCriticalSection(CS[n]);

这是个好主意,不会超载过多的应用程序吗?

第二个问题:

TDateTime(真的Double)和String原子数据吗?我可以阅读(只阅读)它们而不用担心在另一个线程正在写入它时发生冲突吗?

4

1 回答 1

3

尝试serialize访问您的列表/数组。

  • 最简单的序列化方法是使用 aTThreadList来保存记录。 TThreadList存在两个版本,一个通用 inGenerics.Collections和一个非通用 in Classes。对此类列表的所有访问都受到锁定/解锁机制的保护。这种方法是一个好的开始。测量性能,看看是否有问题瓶颈。

  • 另一种方法是让一个线程通过线程安全队列保护所有列表/数组访问。其他试图从列表/数组读取/写入数据的线程在队列上发送一个读/写请求。

    • 对于读取请求,记录的副本在另一个队列中发送到请求线程。
    • 写请求由守护线程提交。

    现在一切都是以最小延迟的事件驱动的。没有关于线程安全的冲突和对因果关系的清晰描述。

    对于线程安全队列,请查看TThreadedQueue您是否拥有 Delphi-XE2 或更新版本。


这是一个概述上述队列方法的示例。

Uses
  Classes,SysUtils,Generics.Collections;
Type
  T = record
    A : Double;
    B : String;
  end;
var
  MyArr : array[1..100] of T;
  GuardingQueue : TThreadedQueue<TProc>;

procedure GuardingThread.Execute;
var
  aProc : TProc;
begin
  while not Terminated do
  begin
    aProc := GuardingQueue.PopItem;
    if not Assigned(aProc) then
      Exit; // Quit thread when nil is sent to the queue
    aProc(); // Execute request
  end;
end;

procedure AccessingThread.Execute;
var
  aLocalQueue : TThreadedQueue<T>;
  aT : T;
begin
  // Make sure aLocalQueue is initialized
  // To get data fom the array ...
  GuardingQueue.PushItem( // read from array
    procedure
    var
      aT : T;
    begin
      aT.A := MyArr[2].A;
      aT.B := MyArr[2].B;
      aLocalQueue.PushItem(aT);
    end
  );
  aT := aLocalQueue.PopItem; // Here is the result from the read request

  // Writing to the array ...
  GuardingQueue.PushItem( // write to array
    procedure
    begin
      MyArr[2].A := 2;
      MyArr[2].B := 'Test';
    end
  );

end;
于 2013-05-01T20:58:58.010 回答