Delphi, secure and fast access to partial elements of a static array
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.
- 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.A; aT.B := MyArr.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.A := 2; MyArr.B := 'Test'; end ); end;