Je sais que les threads Delphi ont été discutés sur de nombreux threads. J'ai essayé de les revoir, mais je n'ai pas trouvé de réponse à ma question.Ce code de thread Delphi est-il correct?
Contexte: J'ai trouvé que la libération d'un TWebBrowser peut prendre 10+ secondes après le navigateur chargé d'Adobe Acrobat Reader DC. Je pense que c'est en train de vérifier les mises à jour ou quelque chose. C'est ennuyant quand on essaie de fermer un formulaire avec un navigateur.
Je pensais que je pourrais avoir un thread de fond libérer le navigateur. J'ai donc déplacé la variable du navigateur vers une variable globale (stockée en privé dans la partie implémentation de l'unité). Une seule de ces formes serait utilisée à la fois. Puis j'ai essayé d'avoir un fil libre en arrière-plan. Ça ne marche pas comme je m'y attendais.
exemple de code
interface
TMyform = class(TForm)
pnlBowserHolder: TPanel;
procedure FormDestroy(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
//WebBrowser : TWebBrowser; <-- moved to global variable
public
{ Public declarations }
end;
implementation
type
TBackgroundBrowserKillerThread = class(TThread)
public
procedure Execute; override;
end;
var
WebBrowser : TWebBrowser;
BrowserKillerThread : TBackgroundBrowserKillerThread;
procedure TfrmLabImageViewer.FormCreate(Sender: TObject);
begin
WebBrowser := TWebBrowser.Create(Self);
TWinControl(WebBrowser).Parent := pnlBowserHolder;
WebBrowser.Align := alClient;
end;
procedure TfrmLabImageViewer.FormDestroy(Sender: TObject);
begin
BrowserKillerThread := TBackgroundBrowserKillerThread.Create(true);
Application.ProcessMessages;
BrowserKillerThread.Execute();
//WebBrowser.Free;
end;
procedure TBackgroundBrowserKillerThread.Execute();
begin
TWinControl(WebBrowser).Parent := nil;
FreeAndNil(WebBrowser);
self.FreeOnTerminate := true;
BrowserKillerThread := nil; //free reference to thread, shouldn't affect ability of self to free itself (?)
end;
Questions:
- Quand j'étape à travers le code FormDestroy en mode de débogage, la ligne contenant BrowserKillerThread.Execute(); prend encore 10 secondes à exécuter. J'avais pensé que cela lancerait l'autre thread et reviendrait immédiatement. Mais ce n'est pas le cas. Ma compréhension est-elle fausse de ce que .execute fait? Ou est-ce que quelque chose de drôle se passe?
- Est-ce que ce que je fais est une mauvaise chose? J'ai lu que la VCL n'est pas thread-safe, et que l'on ne peut/ne doit pas accéder aux objets VCL de l'autre thread. J'espérais que cela ne s'appliquerait pas dans ce cas puisque je libère juste l'objet sans autre interaction prévue.
- Si un thread est libre à la fin, je suppose que cela laisserait mon pointeur BrowserKillerThread pendiller. Alors, est-ce que c'est OK d'assigner zéro à cela comme je le fais?
- Des suggestions sur comment faire mieux?
Merci beaucoup d'avance.
KT
Cela ne marchera jamais. Vous ne pouvez pas accéder à un contrôle VCL de n'importe quel type, sauf le thread principal, et vous ne pouvez pas le créer dans un thread et le détruire dans un autre. Le code que vous avez écrit ne change rien - le navigateur est toujours détruit par le thread principal qui le possède; vous appelez simplement ce code de votre thread (ce qui est faux, sauf si vous le faites via Synchronize). –
En outre ... Vous souhaiterez peut-être revoir tous ces threads. Je parie que vous n'avez pas vu un seul exemple ayant la méthode d'exécution appelée de l'extérieur. Pourquoi? Car alors le code de la méthode execute s'exécuterait dans le contexte du thread qui l'appelle. –
Je ne reçois pas le délai de fermeture de l'application que vous décrivez en utilisant TWebBrower + v.15.023 de Acro Reader DC. Pouvez-vous donner un exemple d'URL qui provoque le retard pour vous? – MartynA