Home > Delphi > Generic intrinsic wrapper

Generic intrinsic wrapper

September 11, 2015 Leave a comment Go to 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…

 

Advertisements
  1. sglienke
    September 12, 2015 at 7:05 am

    I am no MT expert but using that would not be thread safe at all. For example a x.Value := x.Value +1 could result in a totally wrong value because this operation is not atomic and there is no guarantee that nobody else changed the value between the get and set.

    • Jon Lennart Aasenden
      September 12, 2015 at 11:35 am

      You would derive a special class for that:

      Type TMyInt = class(TlockedValue)

      And then add inc() and dec() methods using atomic functions.

  2. September 12, 2015 at 8:02 am

    IMHO, since the access to the resource would be very fast (it is a simple assignment, mostly reference-based), there is no benefit of using TMultiReadExclusiveWriteSynchronizer. The readers would be almost never concurrent with a writer.
    A simple TCriticalSection would behave much better. Ensure you fix the CPU cache line issue as reported by https://www.delphitools.info/2011/11/30/fixing-tcriticalsection/
    If you want to be 100% Delphi, you may try using TMonitor, but I guess it would be less efficient than a TCriticalSection.
    Under Windows, since there won’t be any nested access to the resource, I guess you may try to use light-weight SRW instead. See https://msdn.microsoft.com/en-us/library/windows/desktop/aa904937

    • Jon Lennart Aasenden
      September 12, 2015 at 11:35 am

      I have a switch in the origial class which lets me use TCriticalSection. But for properties and flags which does not require atomic concurrency, it works quite well. But yes, a bog standard TCriticalSection may be required 🙂

  3. September 12, 2015 at 10:59 am

    Right after generics were introduced in Delphi I had an idea about similar approach. Now I am using my custom generic class called TLockedValue which does exactly same as yours. The only difference is I am using TCriticalSection instead.

  4. September 17, 2015 at 11:00 pm

    Hi,
    All of this discussion is good, but I have a simple request.

    I’m currently evaluating various options for a future rewrite of a project and I’m really impressed with the quantity of work and dedication you put in the Smart Mobile Studio. Congratulation! I have spent some time evaluating on it which is very promising.

    That being said, choosing a tool for a project not only implies making sure it is technically good, but also that is will be supported and enhanced in the long run. Unfortunately, it seems not to be very active development, another thing is, you actually have not posted anything about your “kid” over the past three months 😦 for instance.

    I’m a bit worried about SmartMobileStudio future. You could consider hire a fantastic-robo-architect-blogger-Delphi-SmartPascal-TOP-coder Arnaud Bouchez to push SMS to next level, and you could post more about Smart Mobile, hein?

    Best regards.

    • Jon Lennart Aasenden
      May 3, 2016 at 12:32 am

      I would more than welcome A. Bouchez input on the subject, but we are not in a position to hire right now. But indeed, the more the merrier!

  1. No trackbacks yet.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: