I have static array with 100 items type of record:
TMy_Array:array[1..100] of T;
where T is:
T = record
A: double;
B: Date;
C: String;
end;
I have n
similar threads modifying their elements in the TMy_Array
TMy_Array[n].A;
TMy_Array[n].B;
TMy_Array[n].C)`.
N
is close to 100
.
I also have 10 other threads that selectively modify any field TMy_Array
.
To achieve this safely should I use critical sections and here comes the question:
Does use only one critical section will not cause overcrowding of fighting and waiting threads to access the array?
Maybe Can I or should I apply 100 critical sections that will protect access to a particular items in T_Array and the will not block other threads?
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]);
Is this a good idea, doesn't overload too much application?
And second question:
Are the TDateTime
(really Double
) and String
atomic data? Can I read (only read) them without worry about conflicts during another thread is writing to it?
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.
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;