Jump to content
Sign in to follow this  
PatV

multi forms with thread in each

Recommended Posts

Posted (edited)

Found the prob.... it's too quick, I need to introduce a delay in my loop and everything is working

 

now if you have any suggestions, you're welcome

 

 

 

Hi All,

 

I'm using Delphi 10.3

 

As testing, I've a main form 

image.png.765dd1719b35e9a54d022be0cbf79fa1.png

 

when I click on MyForm Create Thread  Button, I launch the code bellow ;

 

image.png.6171e0fbd76b8e457e00b93e3779c5fd.png

 

I create a form TForm.Create(Self)  and I include a frame in it TFrm.Create(Self)

GetTGUIDString simply convert number from TGIUID.NewGuid.ToString to letter, and remove special char to get a random name.

 

In My  Frame, 

 

I have defined a Thread ;

 

  TThDb = class(TThread)
  private
    FOwner    : TComponent;
    FDM       : TFDb;      //
 is a datamodule who will be created within the tread
    FEvent    : TEvent;
    FError    : TFError;
    FRet      : TFRet;
    FAgs      : string;
    FWhenDone : PrcDone;
    procedure InitializeDatabase;
    procedure ConnectToDatabase;
    Procedure WorkOnData;
    function  LoadData : TThDb;
    procedure Execute; override;
  public
    constructor Create(bSuspended : boolean);
    destructor  Destroy; override;
    property Event : TEvent read FEvent write FEvent;
    function WhenDone(aValue : PrcDone) : TThDb;
    function WithAgencies(aValue : string) : TThDb;
    function WithOwner(aValue : TComponent) : TThDb;
    procedure Start;     //
 initialise the connection to the database the first time
    procedure ReStart; // update the variable in the query/procedure
  end;

{------------------------------------------------------------------------------}

procedure TTHDB.InitializeDatabase;
begin
 
CoInitialize(Nil);
  FDM := TFDb.Create(nil);
  FDM.Connection.ReadOnly:=True;
  CoUninitialize;
end;

 

{------------------------------------------------------------------------------}

procedure TTHDB.ConnectToDatabase;
var
  rParam    : rConnectionConfig;
begin
   rParam := GetConnectionConfig;
   rParam.ModuleName := GetTGUIDString;
   FDM.InitConnection(rParam);
   FDM.Connect;
end;

 

{------------------------------------------------------------------------------}

procedure TThDb.ReStart;
begin
  synchronize(
  procedure()
  begin
    LoadData.WorkOnData;
  end);
end;

{------------------------------------------------------------------------------}

 

Procedure TTHDB.WorkOnData;
begin
   if Assigned(FWhenDone) then FWhenDone(FRet);
   Application.ProcessMessages;
end;

{------------------------------------------------------------------------------}


function TThDb.LoadData : TThDb;
var
  aFiles : TFFilesStatus;
begin
  ... some work ...
   FRet.FValue:=TValue.From<TFFilesStatus>(aFiles);
   FRet.FId  := FAgs;
   result:=Self;
end;

{------------------------------------------------------------------------------}

 

procedure TThDb.Start;
begin
  Resume;
end;

 

{------------------------------------------------------------------------------}

 

procedure TThDb.Execute;
begin
   InitializeDatabase; 

  ConnectToDatabase;

  restart;
end;


{------------------------------------------------------------------------------}

{------------------------------------------------------------------------------}

{------------------------------------------------------------------------------}

 

and in the frame constructor I have 

 

constructor TFrm.Create(aOwner: TComponent);
begin
  inherited Create(aOwner);
  FError := TFError.Create;
  FTh:=TThDb.Create(True);
  FTh.WithOwner(Self).WhenDone(UpdateGrid);
end;

 

and launch the following code ;

 

var
 i : integer;
begin
 FTh.Start;
 i:=1;
 while True do
   with FTh do
    if Event.waitfor(0)=wrSignaled then
    begin
       Event.ResetEvent;
       WithAgencies(Format('%0.2d',)).ReStart;
       inc(i);
       if i>99 then i:=1;
       if Terminated then Break;
    end else Application.ProcessMessages;
 FTh.Free;

 

As you see I've a loop ( it's nomal in my test), now If I click again on MyForm Create Thread  Button from the main form, I create another TForm with a TFrrame in, and the thread connected to the database from the previous form/frame  stop working.

 

Is it a normal behaviour or am I missing something ? What I would like of course is that both form with thread in  are still running.

 

Thanks for your help

 

Patrick

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Edited by PatV
correction

Share this post


Link to post

If you want to use a database that requires COM (e.g. via dbGo) inside a thread you have to call CoInitialize at the start of the execute method and CoUninitialize at the end. You are not doing that, your InitializeDatabase method calls CoUnInitialize, so any subsequent use of the database connection may not work as intended.

 

You thread Execute method does not contain a loop, after one pass through the code the thread will exit. Also keep in mind that database connections are usually bound to the thread that created them, so using a dataset bound to the connection created by the thread in another thread (e.g. in the main thread through a Synchronize call) may either not work or involve some internal thread synchronization done by the framework you are using (COM objects using appartment threading are such a case) that may block until the code returns to the message loop.

 

Something else that may foul your design: Creating a datamodule inside a thread is not a problem per se, but if you have design-time links of components on forms, frames, other datamodules to stuff on this datamodule (or vice versa) the way the VCL streaming mechanism resolves them may torpedo your intent. This mechanism is not thread-safe, and it resolves the links using the Name of the component linked to, and it looks for the container (form etc.) in a global list, where it will only find the first created instance of the container, even if you have created several.

Share this post


Link to post

Thanks a lot Peter,

 

I will check the code the follow your advice.

 

Share this post


Link to post

Thanks John !

 

Will take my time to read it.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×