Generic intrinsic wrapper
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…
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.
You would derive a special class for that:
Type TMyInt = class(TlockedValue)
And then add inc() and dec() methods using atomic functions.
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
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 🙂
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.
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.
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!