Archive

Archive for September 11, 2015

Generic intrinsic wrapper

September 11, 2015 7 comments
My new mug, because i have no image on topic

My new mug, because i have no image on topic

Threads. Love’em or hate’em, but sometimes exposing properties between your main Delphi application and your threads can be tricky. There are rules to accessing memory such as “several processes may read from the same memory, but you can never read and write at the same time”. If you get it wrong, you’ll produce a spectacular access violation.

So how do you safely expose properties in your TThread descendants which both the thread and your main VCL application can access? Well take your pick, from a mutex, a semaphore, synchronization calls all the way to brute-force TCriticalSection. You can even cleverly sculpt your properties read / write access so that data can be safely shared. But that is probably more painful than fun.

Keep it simple

My take on the problem is somewhat ad-hoc, depending on the situation and application of course. But a neat trick is to wrap intrinsic datatypes in bridge classes. Now before you state the obvious “hey, that’s what COM variants do!” — remember that Delphi now targets quite a number of platforms, so making stuff “all delphi” has it’s benefits.

And with generic’s it’s not much code either:

TLockedValue<T> = Class(TObject)
private
  FLock:      TMultiReadExclusiveWriteSynchronizer;
  FData:      T;
protected
  function    GetValue:T;
  procedure   SetValue(Value: T);
public
  Property    Value:T read getValue write setValue;
  Constructor Create;virtual;
  Destructor  Destroy;override;
end;
  
Constructor TLockedValue.Create;
begin
  inherited;
  FLock := TMultiReadExclusiveWriteSynchronizer.Create;
end;

Destructor TLockedValue.Destroy;
begin
  FLock.Free;
  inherited;
end;

function TLockedValue.GetValue:T;
begin
  FLock.BeginRead;
  try
    result:=FData;
  finally
    FLock.EndRead;
  end;
end;

procedure TLockedValue.SetValue(Value: T);
begin
  FLock.BeginWrite;
  try
    FData:=Value;
  finally
    FLock.EndWrite;
  end;
end;

Well, the use should be pretty obvious. And it makes even more sense the other way around – when threads want to write values back into the main VCL process. It’s also very handy for state flags which can be altered by multiple running threads (like counters) and so on…