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。これを安全に達成するには、クリティカルセクションを使用する必要があります。ここで質問があります。

クリティカル セクションを 1 つだけ使用することで、競合するスレッドや配列へのアクセスを待機するスレッドが過密になることはありませんか?

おそらく、T_Array 内の特定の項目へのアクセスを保護し、他のスレッドをブロックしない 100 個のクリティカル セクションを適用できますか、または適用する必要がありますか?

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]);

これは良い考えですか?アプリケーションが過負荷になりませんか?

そして2番目の質問:

TDateTime(本当にDouble) とStringアトミック データですか? 別のスレッドが書き込みを行っている間の競合を心配することなく、それらを読み取る (読み取るだけ) ことはできますか?

4

1 に答える 1

3

Try to serialize the access to your list/array.

  • The simplest way to serialize is by using a TThreadList for keeping the records. TThreadList exists in two versions, one generic in Generics.Collections and a non-generic in Classes. All access to such a list is guarded with a lock/unlock mechanism. This approach is a good start. Measure performance, and see if there are any problem bottlenecks.

  • Another approach is to have one thread guard all list/array accesses through a thread-safe queue. Other threads trying to read/write data from the list/array sends a read/write request on the queue.

    • For the reading request, a copy of the record is sent in another queue to the requesting thread.
    • The write request is committed by the guardian thread.

    Now everything is event driven with minimum delay. No conflicts about thread safety and a clear description on causality.

    For a thread-safe queue, look at TThreadedQueue if you have Delphi-XE2 or newer.


Here is an example outlining the above described queue approach.

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 に答える