2010-06-11 2 views
3

мое однопоточное приложение delphi 2009 (еще не совсем законченное) начало испытывать проблемы с приложением Application.ProcessMessages. мое приложение имеет объект TTimer, который запускает каждые 100 мс для опроса внешнего устройства. Я использую Application.ProcessMessages для обновления экрана, когда что-то меняется, поэтому приложение все еще реагирует.Application.ProcessMessages висит?

один из них был в событии OnMouseDown сетки. там, у него были Application.ProcessMessages, которые по существу висели. удаление не было проблемой, за исключением того, что я вскоре обнаружил еще одно приложение Application.ProcessMessages, которое также блокировалось.

Я думаю, что может произойти со мной, так это то, что TTimer - в режиме приложения, который я сейчас отлаживаю - возможно, слишком долго для завершения. я предотвратил правша событий TTimer.OnTimer от повторного ввода и тот же кода (см ниже):

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

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

каких мест было бы плохая практика называть Application.ProcessMessages? Подпрограммы OnPaint приходят в голову как нечто, что не имеет смысла.

любые общие рекомендации?

Я удивлен, увидев возникшую проблему на этом этапе разработки!

+6

Почему это CW? Мне кажется, это довольно конкретный и технический вопрос. –

+0

@ Сертак прав. Вам не нужно отмечать вопрос как сообщество wiki, если только A) вы не хотите приглашать пользователей с низким уровнем репутаций для редактирования вашего вопроса, или B) вы задаете очень субъективный вопрос опроса. Нет никакого правила * против * создания ваших вопросов CW, но вы и люди, которые им отвечают, не получат никакой репутации. –

+0

любая причина, по которой вы не рассматриваете возможность вставки потоков в ваше приложение? –

ответ

2

Благодарю всех вас за ваши комментарии/предложения.

здесь я сделал тестовое приложение, которое имеет процедуру таймера, которая занимает больше времени, чем установленный интервал. когда я нажимаю кнопку1, Application.ProcessMessages висит. Мое решение на данный момент состоит в том, чтобы отключить таймер во время процедуры таймера.

позже мы планируем поместить «коммуникацию устройства» в поток.

спасибо! тр

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

Используйте madExcept, и вы увидите, где затор.

+0

это идея, о которой я не думал, что MadExcept поймает, потому что приложение не кажется висевшим, потому что - в так много способов - похоже, что он работает нормально. –

+0

С madExcept вы также можете увидеть столбец всех потоков. – inzKulozik

5

Моя рекомендация относительно TApplication.ProcessMessages - никогда не используется - там просто не очень удобно его размещать.

Представьте себе, как это называется: ваше приложение запускает цикл сообщений - где последовательно обрабатываются сообщения Windows (созданные ОС, другими приложениями, вашим приложением и т. Д.), А в середине одного из сообщений, вы просто заново запустите весь цикл сообщений, не контролируя, какие сообщения будут обрабатываться, сколько из них будет, если какое-либо из сообщений войдет в свой «собственный цикл сообщений» ... и если они любые проблемы с возвращением или нет. Вот что я называю , предлагая проблемы.

Есть иногда веские причины для обработки некоторых окна сообщений (particularry не вешать другие темы), или обработать все messagess, направленные на конкретное окно, но это может быть достигнуто более тонкими способами, с большим контролем ,

Если вы должны сделать какой-либо обработки в главном GUI потоке, и вы просто хотите обновить интерфейс, вы можете использовать метод TWinControl.Repaint для перерисовки элементов графического пользовательского интерфейса.
Если вы хотите, чтобы приложение реагировало на ввод пользователя, вам в основном нужно использовать потоки backgroud/worker.

Примечание: в Delphi при выполнении любой обработки длины в основном потоке, особенно если ожидание задействовано, вы должны периодически звонить CheckSynchronize, чтобы любые другие потоки синхронизировались с основным потоком - они могут (и, возможно, будет) висеть иначе.
VCL называет это только в том случае, когда приложение переходит в режим ожидания и когда оно обрабатывает сообщение WM_NULL (это суетится, чтобы ничего не делать, что также может вызвать некоторые интересные побочные эффекты).

+0

Благодарим вас за хорошие идеи и перспективы. –

+0

Согласен, что сказал Виктор Свик. Если у вас есть часть кода, который делает длительные вычисления, не рекомендуется делать их в основном потоке. Его плохая практика программирования. – truthseeker

0

кажется ужасный стиль сильно полагаться на логику таймера на основе, и вы понимаете, что, как вы говорите, что вы собираетесь использовать потоки в будущем.

Вот прогрессия в вашем коде:

  1. У вас есть оконное сообщение таймера. он выполняет небольшую работу.
  2. Шесть месяцев спустя на вашем таймере много кода.
  3. вы думаете, что можете улучшить ситуацию, добавив Application.ProcessMessages.

Давайте увеличить немного, по таймеру с 100 мс интервала, для наихудшего случая:

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. 

Вы можете увидеть ... Можете ли вы увидеть .... Можете ли вы увидеть проблема ..... здесь?

W

+0

да; в предыдущих версиях приложения использовался более медленный (1000 мс) таймер. частично через этот цикл развития, они сказали мне опрос. другие части этого проекта уже довольно амбициозны, а также отстают от графика ...нет времени, чтобы «дотянуться» дальше и поместить его в поток еще, тем более, что мой опыт с потоками - почти * 0. спасибо за ваш комментарий! –

Смежные вопросы