Question

Il existe un fil dans mon application Delphi qui possède une boucle d’attente de message. Chaque fois qu'il reçoit un message, il commence à travailler. Voici la procédure d'exécution de ce fil de discussion:

procedure TMyThread.Execute;
begin
  while GetMessage(Msg, 0, 0, 0) and not Terminated do
  begin
    {thread message}
    if Msg.hwnd = 0 then
    begin
      ...
    end
    else
      DispatchMessage(Msg);
  end;
end;

En faisant quelques tests avec mon application, j'ai découvert que la fonction GetMessage dépend du thread principal. J'entends par là que pendant que le thread principal fonctionne, la fonction GetMessage de mon thread ne retourne pas même si un message est en attente de réception par celui-ci (le message est envoyé par un autre thread à l'aide de la fonction PostThreadMessage: PostMessage ( MyThreadId, WM_MyMessage, 0, 0)).

Ce n'est que lorsque le thread principal termine son travail ou que la méthode Application.ProcessMessages est appelée que GetMessage est renvoyé et que mon thread commence à faire son travail. Implémentation de ce type de communication inter-threads J'étais persuadé que mes threads fonctionneraient indépendamment et je ne m'attendrais jamais à ce que la réception des messages envoyés directement à un thread dépende du thread principal.

Lors des tests, j’ai utilisé la fonction WaitForSingleObject dans le thread principal en attendant un événement pendant quelques secondes. C'est à ce moment-là que j'ai remarqué que mon thread ne travaillait pas, même si des messages lui étaient envoyés par un autre thread. Lorsque la fonction WaitForSingleObject a finalement fini d'attendre et que le thread principal est devenu inactif, la fonction GetMessage de mon thread est retournée.

Quelqu'un pourrait-il m'expliquer pourquoi cela fonctionne de cette façon? Y at-il une solution de contournement à cela? Je voudrais que mon fil reçoive des messages de manière indépendante. Tous mes threads sont créés par le thread principal. Est-ce que cela peut être la raison?

Merci de votre aide à l'avance.

Mariusz.

Mghie, vous aviez encore tout à fait raison (vous m'avez aidé avec le matériel de messagerie récemment, vous vous en souviendrez peut-être). Comme vous l'avez suggéré, GetMessage retourne immédiatement, mais le fil se bloque, en fait, lors d'un appel à une méthode de la fenêtre principale:

procedure TMyThread.Execute;
begin
  while GetMessage(Msg, 0, 0, 0) and not Terminated do
  begin
    {thread message}
    if Msg.hwnd = 0 then
    begin
      ...
      if Assigned(FOnCommEventMethod) then
        FOnCommEventMethod(FCommEventsQueueItem);
      ...
    end
    else
      DispatchMessage(Msg);
  end;
end;

FOnCommEventMethod est une méthode d'objet, déclarée comme 'procédure (EventMask: Cardinal) d'objet;' (ce thread gère les événements du port série). Dans ce cas, FOnCommEventMethod s'est vu attribuer une procédure appartenant à la classe de formulaire principale. Lorsque la méthode est appelée par mon thread, le thread se bloque en attendant que le thread principal termine son travail.

Comment ça se fait? Comme vous pouvez le constater, je n’utilise pas la méthode Synchronize () pour appeler cette procédure. Par conséquent, je ne m'attendrais pas à ce que mon thread se synchronise avec le thread principal. Cela se passe t-il implicitement? En passant, je comprends que tous les composants de l’interface graphique ne doivent pas être accédés par d’autres threads que le principal. La méthode Synchronize doit donc être utilisée, mais je ne fais que quelques tests rapides.

Pour en revenir au sujet WaitForSingleObject, je sais que je ne devrais pas l'utiliser, mais ce n'était qu'un test grâce auquel j'ai (par hasard) remarqué le problème.

Merci pour votre aide. Si vous ne m'avez pas aidé, je vais probablement me débarrasser de la messagerie et utiliser des événements, et finalement, je remarquerais que ce n'est pas la raison: -).

Était-ce utile?

La solution

  

Ce n'est que lorsque le thread principal termine son travail ou que la méthode Application.ProcessMessages est appelée que GetMessage est renvoyé et que mon thread commence à faire son travail.

Je doute que ce soit vraiment ce qui se passe. Autant que je sache, les deux boucles de message doivent être indépendantes l'une de l'autre, tant que vous n'utilisez pas d'autres moyens de synchronisation des threads, comme SendMessage () . Êtes-vous sûr que le thread bloque effectivement dans GetMessage () et non dans Synchronize () (qui utilise SendMessage () en interne )?

  

Lors des tests, j’ai utilisé la fonction WaitForSingleObject dans le thread principal, en attendant un événement pendant quelques secondes.

Vous ne devriez jamais utiliser WaitForSingleObject () dans le thread principal avec un délai dépassant 100 millisecondes, ce qui rendrait votre interface utilisateur graphique lente. En fait, je vous conseillerais de ne pas l'utiliser du tout dans le fil principal, car il s'agit simplement d'une interrogation. Poster un message de votre thread de travail à la place.

Autres conseils

Vous pouvez créer une file d'attente de messages pour votre thread. Il suffit d’exécuter le code suivant dans votre sujet:

MSG msg;
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
SetEvent(messageQueueReady);
while (GetMessage(&msg, NULL, 0, 0)) 
{
    ...// do message processing here
}

L'appel à PeekMessage force le système d'exploitation à créer une nouvelle file d'attente de messages pour votre thread. Vous devez vous assurer de la synchroniser, c'est-à-dire que vous devez attendre (par exemple via WaitForSingleObject) pour que l'appel aboutisse avant de poster des messages sur ce fil (par exemple via PostThreadMessage). C’est pourquoi il existe un appel à l’API SetEvent dans l’exemple ci-dessus.

Modifier: Désolé pour l'exemple en C, j'espère que cela vous convient.

Voir http: // groups.google.com/group/borland.public.delphi.language.delphi.win32/browse_thread/thread/cf368834a606321b

Demande de distillation, laissant de nombreux détails épineux dans lesquels se cache le diable: le thread principal (ou VCL) est spécial dans Delphi car beaucoup de choses sous le capot ne sont pas thread-safe, et il les possède tous. Des éléments tels que la boucle de message finissent par attendre en raison d'éléments synchronisés avec le thread VCL sous le capot. Beaucoup de gens ont des théories à ce sujet. La chose qui semble fonctionner le mieux est de garder votre thread VCL aussi léger / réactif que possible afin de minimiser les temps d'attente. Tout le monde est d'accord sur ce point. Certaines personnes ont des idées sur d'autres choses qui pourraient fonctionner mais d'autres pensent qu'elles ne demandent que des ennuis.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top