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 inGenerics.Collections
and a non-generic inClasses
. 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;