2010-06-11 7 views
3

mon application delphi 2009 à thread unique (pas encore terminée) a commencé à avoir un problème avec la suspension de Application.ProcessMessages. mon application a un objet TTimer qui se déclenche toutes les 100 ms pour interroger un périphérique externe. J'utilise Application.ProcessMessages pour mettre à jour l'écran lorsque quelque chose change pour que l'application soit toujours réactive. L'un d'entre eux était dans un événement OnMouseDown de la grille. là-dedans, il y avait un Application.ProcessMessages qui était essentiellement bloqué. enlever ce n'était pas un problème sauf que j'ai bientôt découvert un autre Application.ProcessMessages qui bloquait aussi.Application.ProcessMessages se bloque?

Je pense que ce qui peut m'arriver est que le TTimer est - en mode d'application que je suis en train de déboguer - probablement prendre trop de temps pour terminer. Je l'ai empêché l'événement TTimer.OnTimer clapoteuses de revenir dans le même code (voir ci-dessous):

procedure TfrmMeas.tmrCheckTimer(Sender: TObject); 
begin 
    if m_CheckTimerBusy then 
    exit; 

    m_CheckTimerBusy:=true; 
    try 
    PollForAndShowMeasurements; 
    finally 
    m_CheckTimerBusy:=false; 
    end; 
end; 

quels endroits serait-il une mauvaise pratique d'appeler Application.ProcessMessages? On se souvient des routines OnPaint comme quelque chose qui n'aurait pas de sens.

des recommandations générales?

Je suis surpris de voir ce genre de problème surgir à ce stade du développement!

+6

Pourquoi est-ce un CW? Cela me semble être une question assez spécifique et technique. –

+0

@Sertac a raison. Vous n'avez pas besoin de marquer une question en tant que wiki de communauté, sauf si A) vous souhaitez inviter des utilisateurs à faible rep pour éditer votre question, ou B) vous posez une question de sondage très subjective. Il n'y a pas de règle * contre * faire vos questions CW, mais vous et les personnes qui y répondent ne gagneront aucune réputation. –

+0

une raison pour laquelle vous n'envisagez pas d'introduire le filetage dans votre application? –

Répondre

2

Merci à tous pour vos commentaires/suggestions.

ici j'ai fait une application de test qui a une routine de minuterie qui prend plus de temps que l'intervalle pour lequel elle est définie. quand j'appuie sur button1, Application.ProcessMessages se bloque. ma solution pour l'instant est de désactiver la minuterie pendant la routine de minuterie.

plus tard, nous prévoyons de mettre les "communications de l'appareil" dans un fil.

merci! mp

unit Unit1; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, ExtCtrls, StdCtrls; 

type 
    TForm1 = class(TForm) 
    Timer1: TTimer; 
    Button1: TButton; 
    Memo1: TMemo; 
    procedure Timer1Timer(Sender: TObject); 
    procedure Button1Click(Sender: TObject); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    memo1.Lines.Add('text 1'); 

    // this call blocks 
    Application.ProcessMessages; 

    memo1.Lines.Add('text 2'); 
end; 

procedure TForm1.Timer1Timer(Sender: TObject); 
var 
    iTime:cardinal; 
begin 
    // fix by adding this: timer1.Enabled:=false; 

    iTime:=GetTickCount; 
    while GetTickCount-iTime<200 do 
    ; 

    // fix by adding this: timer1.Enabled:=true; 
end; 

end. 

object Form1: TForm1 
    Left = 0 
    Top = 0 
    Caption = 'Form1' 
    ClientHeight = 286 
    ClientWidth = 426 
    Color = clBtnFace 
    Font.Charset = DEFAULT_CHARSET 
    Font.Color = clWindowText 
    Font.Height = -11 
    Font.Name = 'Tahoma' 
    Font.Style = [] 
    OldCreateOrder = False 
    PixelsPerInch = 96 
    TextHeight = 13 
    object Button1: TButton 
    Left = 8 
    Top = 56 
    Width = 75 
    Height = 25 
    Caption = 'Button1' 
    TabOrder = 0 
    OnClick = Button1Click 
    end 
    object Memo1: TMemo 
    Left = 112 
    Top = 8 
    Width = 297 
    Height = 233 
    Lines.Strings = (
     'Memo1') 
    TabOrder = 1 
    end 
    object Timer1: TTimer 
    Interval = 100 
    OnTimer = Timer1Timer 
    Left = 200 
    Top = 144 
    end 
1

Utilisez madExcept et vous verrez où est l'impasse.

+0

c'est une idée que je n'avais pas cru que MadExcept attraperait parce que l'application ne semble pas accrochée tellement de façons - il semble que ça marche bien. –

+0

Avec madExcept, vous pouvez également voir les callstacks de tous les threads. – inzKulozik

5

Ma recommandation concernant TApplication.ProcessMessages est de jamais l'utiliser - il n'est tout simplement pas un bon point pour le placer. Imaginez ce qu'il appelle: votre application exécute une boucle de message - où les messages Windows (produits par le système d'exploitation, d'autres applications, votre application, etc.) sont séquentiellement traités - et là, au milieu de l'un des messages ... les traitements, il vous suffit de relancer toute la boucle du message, sans avoir le contrôle sur les messages qui seront traités, combien ils seront, si l'un des messages entrera dans sa propre boucle de messages ... et s'ils ont tout problème de réentrance ou non. Voilà ce que j'appelle invitant problème.

Il y a parfois de bonnes raisons de traiter certains messages Windows (particularry pour ne pas bloquer les autres threads), ou pour traiter tous les messagess dirigé vers une fenêtre, mais cela peut être accompli de façon plus subtile, avec plus de contrôle .

Si vous devez faire tout traitement dans le thread GUI principale, et vous voulez juste de mettre à jour l'interface, vous pouvez utiliser la méthode TWinControl.Repaint pour redessiner les éléments de l'interface graphique.
Si vous souhaitez que l'application reste sensible aux entrées utilisateur, vous devez utiliser des threads backgroud/worker. Remarque: en Delphi, tout en faisant un long traitement dans le thread principal, en particulier si l'attente est impliquée, vous devez appeler CheckSynchronize périodiquement, pour permettre à tous les autres threads de se synchroniser avec le thread principal - ils peuvent (et probablement sera) accrocher autrement.
VCL ne l'appelle que lorsque l'application est inactive et lorsqu'elle traite le message WM_NULL (qui est supposé ne rien faire, ce qui peut provoquer des effets secondaires intéressants).

+0

je vous remercie pour quelques bonnes idées et perspectives. –

+0

Je suis d'accord ce que Viktor Svuk a dit. Si vous avez une partie du code qui fait de longs calculs, ce n'est pas une bonne idée de les faire dans le thread principal. C'est une mauvaise pratique de programmation. – truthseeker

0

Il semble un style terrible à appuyer fortement sur la logique basé sur le temps, et vous comprenez que vous dites que vous prévoyez d'utiliser des fils dans l'avenir.

est ici la progression dans votre code:

  1. Vous avez un message de fenêtre de minuterie. ça fait un petit boulot.
  2. Six mois plus tard, votre minuterie exécute beaucoup de code.
  3. vous pensez que vous pourriez améliorer les choses en mettant Application.ProcessMessages.

Let s zoom un peu, sur une minuterie avec un intervalle de 100 ms, pour le pire des cas:

09:00:00.000 - timer event fires 
09:00:00.100 - we are half way through our Timer Event code. We hit an Application.ProcessMessages. 
09:00:00.101 - timer event fires again, but the first time into it, has not yet completed. 
09:00:00.200 - we are half way through our timer event code, the second time, 
and hit APplication.ProcessMessages again. 

Pouvez-vous voir ... Pouvez-vous voir la .... Pouvez-vous voir le ... problème ici?

W

+0

oui; les versions précédentes de l'application utilisaient une minuterie plus lente (1000 ms). à mi-chemin à travers ce cycle de développement, ils m'ont dit le taux de sondage. les autres parties de ce projet sont déjà assez ambitieuses et également en retard ...pas le temps de "toucher" plus loin et de le mettre dans un fil pour le moment - d'autant plus que mon expérience avec les threads est * presque * 0. merci pour votre commentaire! –