Page 1 of 1

ThreadSnapshot in Thread

Posted: Thu Jan 11, 2024 1:56 pm
by ПетрСоболев
The problem is this. For each screenshot I create a new thread. I pass the name of the screenshot I want to receive to the stream. The thread is running and must exit. If I set the thread to complete automatically, the program closes after the first screenshot is taken. Now the code works, but the size of the memory occupied by the program is constantly growing. How to solve this problem?

Code: Select all

procedure TForm1.GetImageBS(Lac,Sid,zadanie,UserID,ZOOM:string);
Var
..
begin
 var FThread : TCEFBrowserThread                  := TCEFBrowserThread.Create(HtmLFileName, 1024, 1024);
      FThread.OnError             := Thread_OnError;
      FThread.OnSnapshotAvailable := Thread_OnSnapshotAvailable;
      FThread.OnTerminate := ThreadTerminated;
      FThread.L:=La;
      FThread.s:=si;
      FThread.UserID:=UID;
      FThread.zadanie:=zadanie;
      FThread.HTML:=HtmLFileName;
      if (ZO<>'') and TrySTRTOINT(z,Temp) then  FThread.z:=zo else  FThread.z:='';
      FThread.Start;
end;
...

procedure TForm1.Thread_OnSnapshotAvailable(Sender: TObject);
var
  TempBitmap : TBitmap;
   JPEG: TJPEGImage;
   SendRes:boolean;
   FThread : TCEFBrowserThread absolute Sender;
begin
  TempBitmap    := nil;

  memo1.Lines.Add('Запущен поток: '+FThread.L+'_'+FThread.s+'_'+FThread.UID+'_'+FThread.zadanie);
  JPEG := TJPEGImage.Create;

  if (FThread <> nil) and FThread.CopySnapshot(TempBitmap) then
    begin
      JPEG.Assign(TempBitmap);
      Image1.Picture.Assign(JPEG);
      if fileexists(extractfilepath(Application.ExeName)+'\BS_image\'+FThread.L+'_'+FThread.s+FThread.z+'.jpg') then
      begin
          if not (FThread.UID='') then
          begin
             ....
          end;
        FThread.TerminateBrowserThread;

        exit;
      end;

      JPEG.SaveToFile(extractfilepath(Application.ExeName)+'\BS_image\'+FThread.L+'_'+FThread.s+FThread.z+'.jpg');
      JPEG.Free;
      if not (FThread.UserID='') then
      begin
       .....
      end;

      FThread.TerminateBrowserThread;
    end;


end;

Re: ThreadSnapshot in Thread

Posted: Thu Jan 11, 2024 7:53 pm
by salvadordf
Hi,

The TerminateBrowserThread call only destroys the browser in the thread but you also need to destroy the thread.

I would recommend using the same thread or a limited number of threads to take all the screenshots.

The WebpageSnapshot demo do this and it uses the same thread when you click the Go button.

Re: ThreadSnapshot in Thread

Posted: Fri Jan 12, 2024 11:38 am
by ПетрСоболев
I need to pass the name of the browser's output snapshot to the stream. And often a situation arises when you need several snapshots at the same time, but one thread cannot cope with this. That's why I create my own stream for everyone. How can I complete my task?

Re: ThreadSnapshot in Thread

Posted: Fri Jan 12, 2024 12:49 pm
by salvadordf
Set FreeOnTerminate to True in TCEFBrowserThread.Create and the thread will free all its resources after the TerminateBrowserThread call.

Re: ThreadSnapshot in Thread

Posted: Sat Jan 13, 2024 4:22 am
by ПетрСоболев
That's what I did. Installed FreeOnTerminate. After the thread completes, the entire program closes. I can't understand why.

Re: ThreadSnapshot in Thread

Posted: Sun Jan 14, 2024 1:08 pm
by salvadordf
Sorry. I forgot that TChromiumCore.FCompHandle needs to be allocated and deallocated in the main application thread.

Set the FreeOnTerminate to FALSE again and destroy the threads using this code :

Code: Select all

  if (FThread <> nil) then
    begin
      if FThread.TerminateBrowserThread then
        FThread.WaitFor;

      FreeAndNil(FThread);
    end;

Re: ThreadSnapshot in Thread

Posted: Sun Jan 14, 2024 2:26 pm
by ПетрСоболев
I wrote the code in the Thread_OnSnapshotAvailable procedure. And nothing works. Threads multiply and do not terminate. Maybe I'm doing something wrong?

Code: Select all

procedure TForm1.Thread_OnSnapshotAvailable(Sender: TObject);
var
  TempBitmap : TBitmap;
   JPEG: TJPEGImage;
   SendRes:boolean;
   FThread : TCEFBrowserThread absolute Sender;
begin
  TempBitmap    := nil;

  memo1.Lines.Add('Запущен поток: '+FThread.L+'_'+FThread.s+'_'+FThread.UID+'_'+FThread.zadanie);
  JPEG := TJPEGImage.Create;

  if (FThread <> nil) and FThread.CopySnapshot(TempBitmap) then
    begin
      JPEG.Assign(TempBitmap);
      Image1.Picture.Assign(JPEG);
      if fileexists(extractfilepath(Application.ExeName)+'\BS_image\'+FThread.L+'_'+FThread.s+FThread.z+'.jpg') then
      begin
          if not (FThread.UID='') then
          begin
          FTelegram.SetUserID(FThread.UID);
          FTelegram.sendPhoto(extractfilepath(Application.ExeName)+'\BS_image\'+FThread.Lac+'_'+FThread.s+FThread.z+'.jpg','Задание:'+FThread.zadanie+' L='+FThread.L+' C='+FThread.s,SendRes);
          end;
        //FThread.TerminateBrowserThread;
        if (FThread <> nil) then
          begin
            if FThread.TerminateBrowserThread then
              FThread.WaitFor;

            FreeAndNil(FThread);
          end;

        exit;
      end;

      JPEG.SaveToFile(extractfilepath(Application.ExeName)+'\BS_image\'+FThread.L+'_'+FThread.s+FThread.z+'.jpg');
      JPEG.Free;
      if not (FThread.UserID='') then
      begin
      FTelegram.SetUserID(FThread.UID);
      FTelegram.sendPhoto(extractfilepath(Application.ExeName)+'\BS_image\'+FThread.L+'_'+FThread.s+FThread.z+'.jpg','Задание:'+FThread.zadanie+' L='+FThread.L+' C='+FThread.s,SendRes);
      end;

      //FThread.TerminateBrowserThread;
        if (FThread <> nil) then
          begin
            if FThread.TerminateBrowserThread then
              FThread.WaitFor;

            FreeAndNil(FThread);
          end;


    end;


end;

Re: ThreadSnapshot in Thread

Posted: Mon Jan 15, 2024 3:31 pm
by salvadordf
Add these points :
  • Keep a list of TCEFBrowserThread instances in the main form and add each new instance as soon as you create it.
  • When a thread must be destroyed send a custom windows message to the main form with the ThreadID as one of the parameters.
  • Implement a procedure in the main form that is executed when the form receives the custom message, search the ThreadID value in the thread list and destroy that thread.
In this way the threads are created and destroyed in the main application thread.