Results 1 to 10 of 10

Thread: Dereferencing problemen

  1. #1

    Dereferencing problemen

    Het porten van 'n connection pool (zie http://edn.embarcadero.com/article/30027 van Delphi naar Lazarus wil niet lukken.
    Ik heb 'n test project gemaakt. Twee problemen doen zich voor:

    1. Het teruggegeven van de connection aan de pool wil niet werken (zoals in Delphi). De reference counter wordt niet verlaagd. (zie ook: http://www.lazarus.freepascal.org/in....html#msg35634).

    2. Als ik de connection expliciet op nil zet (waardoor hij dus teruggegeven wordt aan de pool) worden de resterende regels van de procedure niet meer uitgevoerd.
    Attached Files Attached Files

  2. #2
    Senior Member Thaddy's Avatar
    Join Date
    Dec 2004
    Location
    Amsterdam
    Posts
    2,211
    2. begrijp ik. als delphi dat wel doet is dat een bug in delphi. (finalizing object)

    Je kunt een reeds verdwenen object (database) officieel natuurlijk nooit meer connecten, toch?

    1. zal ik eens testen.
    Werken aan Ansi support voor Windows is verspilde tijd, behalve voor historici.

  3. #3
    Hoezo? Je zou toch 'n verwijzing naar 'n object op nil moeten kunnen zetten zonder dat de routine waarin dat gebeurt crasht?
    Ben benieuwd naar je bevindingen v.w.b. het test projectje.

  4. #4
    mov rax,marcov; push rax marcov's Avatar
    Join Date
    Apr 2004
    Location
    Ehv, Nl
    Posts
    10,357
    Mijn gok is dat TFixedConnection.Getpool fout is. Daar worden classes gemaakt die in class references worden gehouden, en dan vervolgens gestored in interfaces. Stouw daar eens alles in interface references.

    Overigens: kijk enorm uit met je redenaties. "werkend in Delphi, crash in Lazarus, zegt niks. Zilch, noppes, nada". Bug en crash gedrag kunnen komen en gaan afhankelijk van compiler, versie, optimalizatie level enz. Hou dat goed voor ogen tot je extreem zeker bent van je zaak (en dat vereist vrijwel altijd volgen op assembler niveau)

    Er is overigens wel een verschil in interfaces gedrag tussen FPC en Delphi. Delphi behoudt locale references tot het eind van de procedure, FPC tot het eind van het statement. Implementation defined..... (overigens IMHO terecht)
    Last edited by marcov; 28-Jun-11 at 23:38.

  5. #5
    Quote Originally Posted by marcov View Post
    Mijn gok is dat TFixedConnection.Getpool fout is. Daar worden classes gemaakt die in class references worden gehouden, en dan vervolgens gestored in interfaces. Stouw daar eens alles in interface references.
    Class references..., interface references..., quoi? Hoe ziet dat er dan uit?

    Quote Originally Posted by marcov View Post
    Er is overigens wel een verschil in interfaces gedrag tussen FPC en Delphi. Delphi behoudt locale references tot het eind van de procedure, FPC tot het eind van het statement. Implementation defined..... (overigens IMHO terecht)
    Kun je daar 'n voorbeeld van geven? Overigens: ik compileer in {$mode delphi} en verwacht dan dat fpc verschillen opvangt.

    Het lijkt erop dat FPC's implementatie van reference counting eigenlijk usage counting zou moeten heten:

    Code:
    function TFixedConnectionPool.GetConnection: IConnection;
    var
      i: Integer;
      DM: TConnectionModule;
      WaitResult: Integer;
    begin
    Result := nil;
    WaitResult := WaitForSingleObject(Semaphore, FTimeout);
    if WaitResult <> WAIT_OBJECT_0 then
      raise EConnPoolException.Create('Connection pool timeout. '+ 'Cannot obtain a connection');
    EnterCriticalSection(CriticalSection);
    try
      for i := Low(FPool) to High(FPool) do
        begin
          if FPool[i] = nil then
            begin
              DM := TConnectionModule.Create(nil);
              DM.CriticalSection := Self.CriticalSection;
              DM.Semaphore := Self.Semaphore;
              FPool[i] := DM;             <<< D & FPC verhogen rc hier
              FPool[i].Connection.Connected := True;  <<< Alleen FPC verhoogt rc hier
              Result := FPool[i];         <<< D & FPC verhogen rc hier nogmaals verhoogd
              fake := '5';
              Exit;
            end;
          if FPool[i].RefCount = 1 then
          begin
              Result := FPool[i];
              Exit;
            end;
        end; //for
    finally
      //CriticalSection.Leave;
      LeaveCriticalSection(CriticalSection);
    end;
    end;       <<< Alleen FPC verlaagt hier de rc
    Code:
    procedure TTestThread.SetConn(AValue: IConnection);  <<< FPC verhoogd rc hier
    begin
      FConn := AValue;                                               <<< en hier
      FTransaction.Database := FConn.Connection;          <<< en hier nog eens
      FSelect.DataBase := FTransaction.Database;
    end;
    Mogelijk ligt de oplossing in jouw eerste suggestie, maar hoe doe ik dat dan?

  6. #6
    mov rax,marcov; push rax marcov's Avatar
    Join Date
    Apr 2004
    Location
    Ehv, Nl
    Posts
    10,357
    Maak DM een interface (IConnectionModule), en niet een classref (TConnectionModule)

    De verschillen in verhogen in getconnection zijn overigens precies wat ik bedoelde, alleen is het precies andersom als mijn voorbeeld. Je mag alleen er vanuit gaan dat een object leeft als je er een interface reference naar hebt. Over de rest van het refcount gedrag mag je geen aannames maken. De compiler heeft een recht extra temps aan te maken, en ze vrij te geven wanneer hij goed acht, mits ze gedurende het hele statement waar ze aangemaakt worden blijven leven.

    Dus op het moment dat je .refcount nodig hebt, doe je wat fout. Dan ben je workarounds aan het bedenken om niet correcte code semi in de lucht te houden, en dat is op lange termijn een verloren zaak.

    Verder is de kern vuist regel is dat als je ref counting gebruikt, alle referenties naar dat object interfaces dienen te zijn, dus geen menging van interface en classes. Dat wat boven voor DM geldt, geldt dus ook voor fpool en de rest.
    Last edited by marcov; 29-Jun-11 at 13:24.

  7. #7
    Quote Originally Posted by marcov View Post
    Maak DM een interface (IConnectionModule), en niet een classref (TConnectionModule)
    En hoe doe je dat dan?

  8. #8
    mov rax,marcov; push rax marcov's Avatar
    Join Date
    Apr 2004
    Location
    Ehv, Nl
    Posts
    10,357
    Je verandert de T in een I ? :-)

    Ik heb even naar de borland URL gekeken, en wat daar gebeurd ziet er ook niet lekker uit. Dus of ik heb het fout, of die Borland kraam is in principe fout, maar werkt toevallig op Delphi.

    Ik heb echter niet echt veel ervaring met interface code debuggen.
    Last edited by marcov; 29-Jun-11 at 15:28.

  9. #9
    Nou, dat valt wel mee; wat je tot nu toe te berde brengt is indrukwekkend.
    Die Delphi versie bestaat al een aantal jaren, en wordt ook in productie gebruikt. Ik vind het allemaal erg logisch, de Delphi implementatie dus...

  10. #10
    mov rax,marcov; push rax marcov's Avatar
    Join Date
    Apr 2004
    Location
    Ehv, Nl
    Posts
    10,357
    Quote Originally Posted by Elphi View Post
    Die Delphi versie bestaat al een aantal jaren, en wordt ook in productie gebruikt. Ik vind het allemaal erg logisch, de Delphi implementatie dus...
    Het feit dat het lang bestaat pleit meer ertegen dan ervoor. In de tijden voor D6 werd veel minder nauw op dit soort dingen gelet.

    Begrijp me niet verkeerd, ik sluit niet uit dat er iets mis is in FPC, maar deze codebase heeft sowieso een reukje, en je kan er niet zonder meer vanuit gaan dat als het in Delphi werkt, dat het ook correct is. Zelfs als het al tig jaar "productie" draait.

    Uit een eerdere test heb ik nog het volgende bewaard (in DIFF formaat)

    Code:
    --- FixedConnPool.old   Wed Jun 29 16:13:23 2011
    +++ FixedConnPool.pas   Wed Jun 29 16:13:07 2011
    @@ -59,6 +59,7 @@
         //CHANGE
         //To use a connection of another type, change the
         //return type of the Connection function
    +    procedure SetSyncObjects(asemaphore:THandle;ACritSection:TCriticalSection);
         function Connection: TIBConnection;
         function GetRefCount: Integer;
         function GetLastAccess: TDateTime;
    @@ -153,6 +154,7 @@
         {IConnection methods}
         function GetLastAccess: TDateTime;
         function GetRefCount: Integer;
    +    procedure SetSyncObjects(asemaphore:THandle;ACritSection:TCriticalSection);
       public
         { Public declarations }
         constructor Create(AOwner: TComponent); override;
    @@ -228,7 +230,6 @@
     function TFixedConnectionPool.GetConnection: IConnection;
     var
       i: Integer;
    -  DM: TConnectionModule;
       WaitResult: Integer;
     begin
     Result := nil;
    @@ -248,10 +249,8 @@
           //is referencing the object).
           if FPool[i] = nil then
             begin
    -          DM := TConnectionModule.Create(nil);
    -          DM.CriticalSection := Self.CriticalSection;
    -          DM.Semaphore := Self.Semaphore;
    -          FPool[i] := DM;
    +          FPool[i] := TConnectionModule.Create(nil);
    +          FPool[i].SetSyncObjects(Semaphore,CriticalSection);
               FPool[i].Connection.Connected := True;
               Result := FPool[i];
               Exit;
    En dan nog ff setsyncobjects implementeren. (doet niks anders dan parameters aan velden assignen)

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •