Je suis nouveau à multithreading, mais pas un novice complet. J'ai besoin d'effectuer un appel à un service Web dans un thread de travailleur.
dans le fil principal, j'ai une forme (Tform) avec un membre de données privé (chaîne privée) que seul le fil du travailleur écrira (je passe le pointeur sur le fil avant qu'il ne reprenne). Lorsque le fil du travailleur a terminé son appel de service Web et écrit la réponse résultante XML au membre privé sur le formulaire, le thread du travailleur utilise PostMessage pour envoyer un message à la poignée du formulaire (que j'ai également transmis dans le fil avant de reprendre). < / p> Cela fonctionne bien, mais maintenant je veux faire la même chose edit strud> p> Ce que je veux vraiment, c'est le code (si possible) Permettez-moi de remplacer la ligne p> avec p>
3 Réponses :
J'ai utilisé cette technique avant de réussir: Envoyer des messages à des messages non Applications fenêtres P>
Fondamentalement, utilisez un deuxième thread en tant que pompe à message sur une poignée obtenue via AllateHwnd. Ceci est certes irritant et vous feriez mieux d'utiliser une bibliothèque pour gérer tous les détails. Je préfère omnithreadlibrary mais il y en a d'autres - voir Comment choisir entre les différentes façons de faire de la filetage dans Delphi? et < Un href = "https://stackoverflow.com/questions/670641/delphi-threading-frameworks"> Delphi - Frameformes de filetage . P>
+1 pour ne pas réinventer la roue. Regarde omnithreadlibrary.
Allocathwnd a fait le travail. Merci Moz.
Vous pouvez allouer votre propre poignée avec AllocHWND et utiliser cela comme une cible postmessage.
TTestThread = class(TThread)
private
FSignalShutdown: boolean;
// hidden window handle
FWinHandle: HWND;
protected
procedure Execute; override;
// our window procedure
procedure WndProc(var msg: TMessage);
public
constructor Create;
destructor Destroy; override;
procedure PrintMsg;
end;
constructor TTestThread.Create;
begin
FSignalShutdown := False;
// create the hidden window, store it's
// handle and change the default window
// procedure provided by Windows with our
// window procedure
FWinHandle := AllocateHWND(WndProc);
inherited Create(False);
end;
destructor TTestThread.Destroy;
begin
// destroy the hidden window and free up memory
DeallocateHWnd(FWinHandle);
inherited;
end;
procedure TTestThread.WndProc(var msg: TMessage);
begin
if Msg.Msg = WM_SHUTDOWN_THREADS then
// if the message id is WM_SHUTDOWN_THREADS
// do our own processing
FSignalShutdown := True
else
// for all other messages call
// the default window procedure
Msg.Result := DefWindowProc(FWinHandle, Msg.Msg,
Msg.wParam, Msg.lParam);
end;
Que Allocathwnd n'est pas un fil de sécurité est une source de beaucoup d'irritation. Il semble que Embarcadero ne change pas leur politique. J'utilise mon propre code d'accrochage noddy pour remplacer Allochwnd au moment de l'exécution avec une version protégée par une section critique.
@David: D'accord, mais il y a des choses dans leur code qui sont beaucoup plus irritantes et qui ne sont toujours pas réparées :) Je serais heureux si cela ne serait que Allocathwnd.
Tant que le nouveau thread est créé par le fil de l'interface graphique, il n'y a aucun problème avec ce code. Le constructeur fonctionne dans le contexte du fil qui l'appelle.
Alternatives basées sur l'utilisation d'un événement:
Utilisez à l'onduleur du fil (déjà présent ) En combinaison avec un drapeau: p>
TMyDataModule = class(TDataModule)
private
procedure OnWebServiceCallComplete(Sender: TObject);
...
TMyThread = class(TThread)
public
property TerminateFlag: Integer ...
...
procedure TMyDataModule.StartWorkerThread;
...
MyWorkerThread.OnTerminate := <Self.>OnWebServiceCallComplete;
...
procedure TMyDataModule.OnWebServiceCallComplete(Sender: TObject);
begin
if MyWorkerThread.TerminateFlag = WEBCALL_COMPLETE then
...
end;
Ajoutez une nouvelle propriété d'événement à la classe de thread dans laquelle vous pouvez fournir le drapeau sous forme de paramètre pour indiquer le résultat de terminaison / thread. Quelque chose comme montré ici . Assurez-vous de synchroniser l'appel de l'événement. Ou oubliez le paramètre et appelez simplement l'événement si l'exécution est terminée de manière gracieuse (comme si vous le faisez maintenant). P> LI> ol> p>
J'apprécie vraiment cette alternative. Il semble plus élégant. Je vais l'essayer.
À la deuxième pensée, l'utilisation de messages est mon modèle préféré. Merci quand même.