Jump to content

fastbike

Members
  • Content Count

    21
  • Joined

  • Last visited

Community Reputation

0 Neutral

Technical Information

  • Delphi-Version
    Delphi 11 Alexandria

Recent Profile Visitors

512 profile views
  1. fastbike

    Access

    A post with a couple of code blocks
  2. fastbike

    Locking an Object

    Blame the scattered posts on the forum software consistently refusing to allow me to post anything here two days ago - each time posts with codeblocks were tagged as spam and after editing the attempted post I received notification that I had exceeded the number of posts - which is just way beyond frustrating. I will start another thread on Stackoverflow since this one has become very hard to follow.
  3. fastbike

    Locking an Object

    There is one global object. It has a method that loads the data into it (Reload). There is an internal flag to say if the data has been loaded. There is another method to access that data (GetOperation) - client threads (from IIS so I do not create these consumer threads) call this method which needs to block until the data has been loaded which is signified by the internal flag being set. Is TMonitor the correct synchronisation structure here ?
  4. fastbike

    Locking an Object

    And now that the forum filters have relaxed, am I using the TMonitor record correctly to lock the global object until it has been populated ?
  5. fastbike

    Locking an Object

    And finally a much improved version of the method that should not return until the Reload method above has done its thing. function TFHIROperationFactory.GetOperation(Id: string): IFHIROperationDefintion; begin Log.Debug('GetOperation for %s', [Id], DefaultLogTag); if not FOperationsLoaded then begin Log.Debug('Waiting for Operations to be loaded', DefaultLogTag); TMonitor.Enter(Self); try for var I := 0 to Settings.ReadInteger('Global', 'RetryOperationsReload', 15) do // prevent run away loop begin while not FOperationsLoaded do TMonitor.Wait(Self, 250); end; if not FOperationsLoaded then raise EFHIRExceptionServer.Create('Could not load FHIR Operations, check settings Global|RetryOperationsReload'); finally TMonitor.Exit(Self); end; end; if not FRegisteredOperations.TryGetValue(Id, Result) then begin raise EFHIRExceptionServer.CreateFmt('FHIR Operation with id %s not registered', [Id]); end; end;
  6. fastbike

    Locking an Object

    An improved version of the Reload method (called either independently via an URL endpoint) or as part of the lazy creation of the object (see above) This one does a pulse all to advise any waiting threads that the global objects is now unlocked. /// <summary>Load (or reload) the OperationDefinition resources from *.xml files, and populate the type mapper</summary> procedure TFHIROperationFactory.Reload; begin TMonitor.Enter(Self); try FOperationsLoaded := false; LoadOperationDefinitions; FOperationsLoaded := true; TMonitor.PulseAll(Self); finally TMonitor.Exit(Self); end; end;
  7. fastbike

    Locking an Object

    And the code that gets called by other worker threads when they need a IFHIROperationDefintion instance. I think the TMonitor code is of no effect - in hindsight it should actually be sitting there and spinning (via TMonitor.Wait ? ) until the Reload method has set the lock variable (FOperationsLoaded). I'll provide an improved implementation of these two methods in the next post for inspection and comment. function TFHIROperationFactory.GetOperation(Id: string): IFHIROperationDefintion; begin if not FOperationsLoaded then begin Log.Debug('Waiting for Operations to be loaded', DefaultLogTag); TMonitor.Enter(Self); try if not FOperationsLoaded then begin Reload; end; finally TMonitor.Exit(Self); end; end; if not FRegisteredOperations.TryGetValue(Id, Result) then begin raise EFHIRExceptionServer.CreateFmt('FHIR Operation with id %s not registered', [Id]); end; end;
  8. fastbike

    Locking an Object

    And the code that does the initial loading / reloading of the xml files and creation of the implementation objects ///<summary>Load (or reload) the OperationDefinition resources from *.xml files</summary> procedure TFHIROperationFactory.Reload; begin FOperationsLoaded := false; TMonitor.Enter(Self); try LoadOperationDefinitions; // a helper method that reads files from a directory, creates objects and adds to the dictionary FOperationsLoaded := true; finally TMonitor.Exit(Self); end; end;
  9. fastbike

    Locking an Object

    Some vanilla code for constructor / destructor constructor TFHIROperationFactory.Create; begin inherited Create; FRegisteredOperations := TDictionary<string, IFHIROperationDefintion>.Create; end; destructor TFHIROperationFactory.Destroy; begin FRegisteredOperations.Free; inherited; end; [Click and drag to move]
  10. fastbike

    Locking an Object

    My implementation, very similar but with a function that @Remy Lebeau helped me write. The singleton can only be accessed via the global function pointer as all of this code is in the implementation section. // global singleton variables/methods var _FHIROperationFactory: IFHIROperationFactory; function GetDefaultFHIROperationFactory: IFHIROperationFactory; var newFHIRFactory: IFHIROperationFactory; begin if _FHIROperationFactory = nil then begin { The object does not exist yet. Create one. } newFHIRFactory := TFHIROperationFactory.Create; { It is possible another thread also created one, so get the first} InterlockedCompareExchangeIntf(IInterface(_FHIROperationFactory), newFHIRFactory, nil); _FHIROperationFactory.Reload; end; Result := _FHIROperationFactory; end; initialization // assign an implemntation method to the global function pointer FHIROperationFactory := GetDefaultFHIROperationFactory; end.
  11. fastbike

    Locking an Object

    I have a similar implementation but am having trouble posting replies to this thread ion this forum. It seems the filters are rejecting my posts for reasons unknown.
  12. fastbike

    Access

    I'm getting blocked - my responses are getting marked as "spam", or looks like some rate limiting going on. I walk away.
  13. fastbike

    Locking an Object

    Next up there is a default implementation which can read xml files from disk and create a list of IFHIROperationDefintion (worker) objects. // concrete class declared in the implementation part of the unit, so only accessible via the global function type /// <summary>Concrete class for FHIR Operations </summary> TFHIROperationFactory = class(TInterfacedObject, IFHIROperationFactory) private FOperationsLoaded: Boolean; FRegisteredOperations: TDictionary<string, IFHIROperationDefintion>; procedure LoadOperationDefinitions; protected { IFHIROperationFactory } function GetOperation(Id: string): IFHIROperationDefintion; procedure Reload; public constructor Create; destructor Destroy; override; end;
  14. fastbike

    Locking an Object

    Here's the declaration of the type and a global function to an instance of that type // interface to provide functionality that will be implemented by a global object type /// <summary>Register of supported FHIR Operations</summary> IFHIROperationFactory = interface ['{6E207FA9-CBB8-4F7A-A54F-D90621B601C8}'] function GetOperation(Id: string): IFHIROperationDefintion; procedure Reload; end; // a global pointer to a function that returns an instance (allows mocking for testing other parts of the code) var FHIROperationFactory: function: IFHIROperationFactory;
  15. fastbike

    Locking an Object

    Thanks for the comments and suggestions. I'll copy in some simplified code snippets - I think I have misunderstood how TMonitor would protect multiple threads from accessing methods of a global object. I'm trying to post an example here and keep getting a message saying my post appears to be spam ! I'll try posting each separately so apologies in advance for having to read through it all.
×