Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > Программа и интерфейс
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #16  
Старый 12.03.2014, 17:24
Аватар для poli-smen
poli-smen poli-smen вне форума
Профессионал
 
Регистрация: 06.08.2012
Адрес: Кривой Рог
Сообщения: 1,791
Версия Delphi: Delphi 7, XE2
Репутация: 4415
По умолчанию

Цитата:
Сообщение от novashdima
Посмотрите, все ли правильно, а то вдруг утечки памяти какие и что-то подобное.
Иногда прога подвисает после приостановки и иногда возникает floating point division by zero на строке 73.
И когда останавливаю и потом заново стартую обработка начинается с прошлого места, и это связано с ошибкой выше, хотя вроде как все, что можно чищу.
Код:
.....
procedure TForm1.StartProcessClick(Sender: TObject);
begin
  if AnalysThread.Suspended
  then begin
         AnalysThread.Resume;
         *****
         end
  else begin
        AnalysThread.Suspend;
        ******
        end;
end;
Не рекомендуется насильно приостанавливать из одного потока другой. Об этом написано в справке MSDN и по-русски. Лучше всего сообщить потоку что он должен быть приостановлен и тогда сам поток дойдя до безопасной точки сам себя приостановит.
Цитата:
Сообщение от novashdima
Код:
   Position := Round(Form1.Gauge.MaxValue / Form1.ListBox.Count * i);
Здесь может быть деление на ноль.

И ещё немного смущают манипуляции с StringList. Создавать его лучше по-нужде, перед использованием проверять на наличие и разрушать в завершении приложения. Либо же создавать однажды при запуске приложения и разрушать при завершении приложения.
Ответить с цитированием
  #17  
Старый 12.03.2014, 17:52
novashdima novashdima вне форума
Новичок
 
Регистрация: 05.02.2010
Адрес: Украина, Киев
Сообщения: 64
Версия Delphi: XE3, XE4
Репутация: 10
По умолчанию

Цитата:
Сообщение от poli-smen
Не рекомендуется насильно приостанавливать из одного потока другой. Лучше всего сообщить потоку что он должен быть приостановлен и тогда сам поток дойдя до безопасной точки сам себя приостановит.
И где эта безопасная точка находится? При выполнении в форе произойдет остановка? Как сообщить?
Сделать еще один флаг, и вместо фора поставить вайл с проверкой флага? Просто одно действие в форе может выполняться достаточно долго и будет впечатление что или прога зависла или вообще никак не реагирует на кнопку.
Цитата:
Сообщение от poli-smen
Здесь может быть деление на ноль.
Добавлю проверку, но вообще по логике программы не должна вызывать процедура обработки, если данные пустые.
Цитата:
Сообщение от poli-smen
И ещё немного смущают манипуляции с StringList. Создавать его лучше по-нужде, перед использованием проверять на наличие и разрушать в завершении приложения. Либо же создавать однажды при запуске приложения и разрушать при завершении приложения.
Так вот я и создаю стринглист при создании формы и убиваю при уничтожении формы, посмотрите на исходник, который я приложил.

Последний раз редактировалось novashdima, 12.03.2014 в 17:56.
Ответить с цитированием
  #18  
Старый 12.03.2014, 18:14
icWasya icWasya вне форума
Местный
 
Регистрация: 09.11.2010
Сообщения: 499
Репутация: 10
По умолчанию

Код:
if Assigned(StringList) then
    FreeAndNil(StringList); 
Внутри FreeAndNil проверка на Nil уже есть, та кчто можно писать просто
Код:
 FreeAndNil(StringList); 

Далее
Я уже спрашивал - что с чем синхронизируется спомощью CriticalSection ?
Если она используется только в одном потоке, то она не нужна.
Ответить с цитированием
  #19  
Старый 12.03.2014, 18:18
Аватар для poli-smen
poli-smen poli-smen вне форума
Профессионал
 
Регистрация: 06.08.2012
Адрес: Кривой Рог
Сообщения: 1,791
Версия Delphi: Delphi 7, XE2
Репутация: 4415
По умолчанию

Цитата:
Сообщение от novashdima
И где эта безопасная точка находится?
Ну это когда поток отпустит все критические секции и другие объекты.
Например здесь:
Код:
procedure MyThread.Execute;
begin
//  inherited; Это здесь не нужно
  while not Terminated do
  begin
    // Безопасная точка - проверяем не нужно ли приостановиться (Suspend)
     Analys;
  end;
end;
Цитата:
Сообщение от novashdima
При выполнении в форе произойдет остановка? Как сообщить?
Сделать еще один флаг, и вместо фора поставить вайл с проверкой флага? Просто одно действие в форе может выполняться достаточно долго и будет впечатление что или прога зависла или вообще никак не реагирует на кнопку.
Можно использовать для оповещения например сигнал TEvent, а проверять не приостановился ли поток через TEvent.WaitFor(100).
Цитата:
Сообщение от novashdima
Добавлю проверку, но вообще по логике программы не должна вызывать процедура обработки, если данные пустые.
Всегда лучше перестраховаться
Цитата:
Сообщение от novashdima
Так вот я и создаю стринглист при создании формы и убиваю при уничтожении формы, посмотрите на исходник, который я приложил.
Если так, то вот этого делать не нужно:
Цитата:
Сообщение от novashdima
Код:
procedure TForm1.FormCreate(Sender: TObject);
begin
  try
.....
    ******
  except
    if Assigned(StringList) then
      FreeAndNil(StringList);
    *****
  end;
end;
Т.е. при запуске приложения создали при завершении приложения разрушили, а посреди никаких созданий и разрушений быть не должно, в том числе и при ошибках.
Ответить с цитированием
  #20  
Старый 12.03.2014, 18:32
novashdima novashdima вне форума
Новичок
 
Регистрация: 05.02.2010
Адрес: Украина, Киев
Сообщения: 64
Версия Delphi: XE3, XE4
Репутация: 10
По умолчанию

Цитата:
Сообщение от poli-smen
Ну это когда поток отпустит все критические секции и другие объекты.
Например здесь:
Код:
procedure MyThread.Execute;
begin
//  inherited; Это здесь не нужно
  while not Terminated do
  begin
    // Безопасная точка - проверяем не нужно ли приостановиться (Suspend)
     Analys;
  end;
end;
так у меня процедура анализ вызывается только при начале обработки, соответственно проверка выполниться только один раз до какой-либо работы потока.
Цитата:
Сообщение от poli-smen
Можно использовать для оповещения например сигнал TEvent, а проверять не приостановился ли поток через TEvent.WaitFor(100).
Вот это уже хорошая идея, надо будет попробовать.
Цитата:
Сообщение от poli-smen
Всегда лучше перестраховаться.
Я обычно очень много проверок ставлю, но потом постепенно улучшаю правило проверки и убираю ненужное после этого.
Цитата:
Сообщение от poli-smen
Если так, то вот этого делать не нужно:Т.е. при запуске приложения создали при завершении приложения разрушили, а посреди никаких созданий и разрушений быть не должно, в том числе и при ошибках.
Так этот код выполняется только если вылетело исключение, там же try except, если все завершилось удачно то ничего не разрушается
Ответить с цитированием
  #21  
Старый 12.03.2014, 18:59
Аватар для poli-smen
poli-smen poli-smen вне форума
Профессионал
 
Регистрация: 06.08.2012
Адрес: Кривой Рог
Сообщения: 1,791
Версия Delphi: Delphi 7, XE2
Репутация: 4415
По умолчанию

Цитата:
Сообщение от novashdima
так у меня процедура анализ вызывается только при начале обработки, соответственно проверка выполниться только один раз до какой-либо работы потока.
Метод Execute это уже и есть работа потока, так что проверка выполнится уже во время работы параллельного потока, и не один раз - там же цикл "while not Terminated do", т.е. пока поток не попросят завершиться этот цикл будет вертеться. Хотя конечно ничто не мешает поставить проверку и после вызова Analys
Цитата:
Сообщение от novashdima
Вот это уже хорошая идея, надо будет попробовать.
Можно сделать ещё проще - с помощью InterlockedExchange:
Код:
type
  MyThread = class(TThread)
  private
    FSuspendNeeded: LongBool;
    procedure SetSuspendNeeded(const Value: LongBool);
  public
    property SuspendNeeded: LongBool read FSuspendNeeded write SetSuspendNeeded;
  protected
    procedure Execute; override;
  end;

{ MyThread }

procedure MyThread.Execute;
begin
  while not Terminated do
  begin
    Analys;
    if SuspendNeeded then Suspend;
  end;
end;

procedure MyThread.SetSuspendNeeded(const Value: LongBool);
begin
  if FSuspendNeeded <> Value then
    Windows.InterlockedExchange(LongInt(FSuspendNeeded), LongInt(Value));
end;
Таким образом в главном потоке можно без проблем просить приостановки параллельного потока:
Код:
AnalysThread.SuspendNeeded := True;
А через свойство AnalysThread.Suspended периодически проверять не приостановлся ли уже поток.
Цитата:
Сообщение от novashdima
Так этот код выполняется только если вылетело исключение, там же try except, если все завершилось удачно то ничего не разрушается
Но при ошибке то разрушается. И тем временем уже созданный параллельный поток будет пытаться работать с уже разрушенным объектом.
Ответить с цитированием
  #22  
Старый 12.03.2014, 19:06
novashdima novashdima вне форума
Новичок
 
Регистрация: 05.02.2010
Адрес: Украина, Киев
Сообщения: 64
Версия Delphi: XE3, XE4
Репутация: 10
По умолчанию

Цитата:
Сообщение от poli-smen
Но при ошибке то разрушается. И тем временем уже созданный параллельный поток будет пытаться работать с уже разрушенным объектом.
Почему это? Он только создан будет, но он будет приостановлен и не запуститься, пока я ему не передам Resume.
Насчет остального спасибо, завтра буду пробовать, а то надо на работу бежать уже.
Ответить с цитированием
  #23  
Старый 12.03.2014, 19:12
Аватар для poli-smen
poli-smen poli-smen вне форума
Профессионал
 
Регистрация: 06.08.2012
Адрес: Кривой Рог
Сообщения: 1,791
Версия Delphi: Delphi 7, XE2
Репутация: 4415
По умолчанию

Цитата:
Сообщение от novashdima
Почему это? Он только создан будет, но он будет приостановлен и не запуститься, пока я ему не передам Resume.
В любом случае зачем его при возникновении исключения разрушать если при завершении приложения он будет всё равно разрушен. Лишний код на который потом (при разрастании приложения) можно наступить как на грабли.
Ответить с цитированием
  #24  
Старый 14.03.2014, 23:56
novashdima novashdima вне форума
Новичок
 
Регистрация: 05.02.2010
Адрес: Украина, Киев
Сообщения: 64
Версия Delphi: XE3, XE4
Репутация: 10
По умолчанию

Цитата:
Сообщение от poli-smen
Таким образом в главном потоке можно без проблем просить приостановки параллельного потока
Вроде как поток останавливается, но прогрессбар и мемо продолжают обновляться...

ап. поставил в цикле обработки в процедуре Анализ проверку на AnalysThread.Suspended, он всегда равен false, запустил программу, запустил обработку данных, приостановил выполнение и оказывается SuspendNeeded меняется на true, но поток не приостанавливается. Мне еще и в сам цикл во время обработки данных впихнуть проверку значения SuspendNeeded?

Да, еще всегда интересовали, можно настроить отладчик так, чтобы при отладке я трассировал только код своей программы, не заходя в System.SysUtils и тому подобные?
Ответить с цитированием
  #25  
Старый 15.03.2014, 01:26
Аватар для poli-smen
poli-smen poli-smen вне форума
Профессионал
 
Регистрация: 06.08.2012
Адрес: Кривой Рог
Сообщения: 1,791
Версия Delphi: Delphi 7, XE2
Репутация: 4415
По умолчанию

Цитата:
Сообщение от novashdima
ап. поставил в цикле обработки в процедуре Анализ проверку на AnalysThread.Suspended, он всегда равен false, запустил программу, запустил обработку данных, приостановил выполнение и оказывается SuspendNeeded меняется на true, но поток не приостанавливается.
Ну так SuspendNeeded и не останавливает поток, оно только сообщает потоку, что ему следует приостановиться сразу же как он дойдёт до ближайшей безопасной точки.
Цитата:
Сообщение от novashdima
Мне еще и в сам цикл во время обработки данных впихнуть проверку значения SuspendNeeded?
Если там есть безопасная точка. Чем чаще будут проверки значения SuspendNeeded, тем быстрее поток будет реагировать на просьбу приостановиться.
Цитата:
Сообщение от novashdima
Да, еще всегда интересовали, можно настроить отладчик так, чтобы при отладке я трассировал только код своей программы, не заходя в System.SysUtils и тому подобные?
Сними в настройках проекта галочку: Меню -> "Project" -> "Options..." -> "Compiler" -> "Debugging" -> "Use Debug DCUs" (Это в Delphi 7. В XE3 должно быть примерно так же.)
После чего сохрани и перестрой проект: Меню -> "Project" -> "Build All Projects"
Ответить с цитированием
  #26  
Старый 15.03.2014, 02:28
novashdima novashdima вне форума
Новичок
 
Регистрация: 05.02.2010
Адрес: Украина, Киев
Сообщения: 64
Версия Delphi: XE3, XE4
Репутация: 10
По умолчанию

Цитата:
Сообщение от poli-smen
Ну так SuspendNeeded и не останавливает поток, оно только сообщает потоку, что ему следует приостановиться сразу же как он дойдёт до ближайшей безопасной точки.Если там есть безопасная точка. Чем чаще будут проверки значения SuspendNeeded, тем быстрее поток будет реагировать на просьбу приостановиться.
Так мне самому нужно указывать эту самую безопасную точку?
Каким образом в коде обработки указать, что поток может быть приостановлен?
Цитата:
Сообщение от poli-smen
Сними в настройках проекта галочку: Меню -> "Project" -> "Options..." -> "Compiler" -> "Debugging" -> "Use Debug DCUs" (Это в Delphi 7. В XE3 должно быть примерно так же.)
После чего сохрани и перестрой проект: Меню -> "Project" -> "Build All Projects"
Галочка итак снята
Изображения
Тип файла: png Снимок.PNG (55.6 Кбайт, 4 просмотров)
Ответить с цитированием
  #27  
Старый 15.03.2014, 03:58
Аватар для poli-smen
poli-smen poli-smen вне форума
Профессионал
 
Регистрация: 06.08.2012
Адрес: Кривой Рог
Сообщения: 1,791
Версия Delphi: Delphi 7, XE2
Репутация: 4415
По умолчанию

Цитата:
Сообщение от novashdima
Так мне самому нужно указывать эту самую безопасную точку?
Ну конечно же самому. Здесь всего 2 варианта. Либо в наглую остановить поток через Suspend. Или же установить некий флаг сообщающий потоку, что он должен быть остановлен, тогда поток в тех местах в которых может безопасно остановится должен проверять этот флаг и при необходимости останавливаться. Например, если поток сейчас выполняет запись на лазерный диск (DVD-R), а мы его внаглую остановим через Suspend, то вместе с ним остановится и запись диска, которая уже вряд-ли продолжится если вновь запустить приостановленный поток, а недописанную болванку можно выкинуть.
Цитата:
Сообщение от novashdima
Каким образом в коде обработки указать, что поток может быть приостановлен?
Проверять флаг SuspendNeeded и при необходимости самого себя останавливать с помощью Suspend
Цитата:
Сообщение от novashdima
Галочка итак снята
В Delphi 7 снятия этой галочки достаточно. Видимо в XE3 что-то ещё намудрили - нужно с настройками XE3 отдельно разбираться.
Ответить с цитированием
  #28  
Старый 15.03.2014, 16:57
novashdima novashdima вне форума
Новичок
 
Регистрация: 05.02.2010
Адрес: Украина, Киев
Сообщения: 64
Версия Delphi: XE3, XE4
Репутация: 10
По умолчанию

Цитата:
Сообщение от poli-smen
Ну конечно же самому.
Ну я так и думал, сделал, все работает, разве что есть вопрос, не лишние ли действия делаю, вот код:
Код:
procedure TForm1.StartProcessClick(Sender: TObject);
begin
  if AnalysThread.Suspended
  then begin
        AnalysThread.SuspendNeeded := False;
        AnalysThread.Resume;
       end
  else begin
        AnalysThread.SuspendNeeded := True;
       end;
end;

procedure TForm1.StopProcessClick(Sender: TObject);
begin
  AnalysThread.Terminate;
  ClearForm;
end;

procedure MyThread.Analys;
begin
  try
   if AnalysThread.Terminated then Exit;
   if AnalysThread.SuspendNeeded then AnalysThread.Suspend;
   CriticalSection.Enter;
   for i := 0 to Form1.ListBox.Count - 1 do
    begin
    if SuspendNeeded then AnalysThread.Suspend;
    .....
  finally
      Synchronize(Form1.ClearForm);
  end;
end;

procedure MyThread.Execute;
begin
  while not Terminated do
  begin
    if SuspendNeeded then Suspend;
    Analys;
  end;
end;

procedure MyThread.SetSuspendNeeded(const Value: LongBool);
begin
  if FSuspendNeeded <> Value then
     InterlockedExchange(LongInt(FSuspendNeeded), LongInt(Value));
end;

procedure MyThread.UpdateGauge;
begin
  if not AnalysThread.Suspended
  then Form1.Gauge.Progress := Position;
end;

procedure MyThread.UpdateMemo;
begin
  if not AnalysThread.Suspended
  then begin
        Form1.Memo.Text := StringList.Text;
        Form1.Memo.Refresh;
       end;
end;
Ответить с цитированием
  #29  
Старый 17.03.2014, 11:51
icWasya icWasya вне форума
Местный
 
Регистрация: 09.11.2010
Сообщения: 499
Репутация: 10
По умолчанию

Просто правила хорошего тона
Код:
procedure MyThread.UpdateGauge;
begin
  if not AnalysThread.Suspended
   then Form1.Gauge.Progress := Position; 
end; 
Внутри методов MyThread не рекомендуется использовать переменную AnalysThread - лучше писать Self, во так
Код:
procedure MyThread.UpdateGauge;
begin
  if not Self.Suspended
   then Form1.Gauge.Progress := Position; 
end; 
или ничего вообще, вот так
Код:
procedure MyThread.UpdateGauge;
begin
  if not Suspended
   then Form1.Gauge.Progress := Position; 
end; 
Ответить с цитированием
  #30  
Старый 17.03.2014, 18:46
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
Радость

а разве использование глобальной Form1 в потоке хороший тон?
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 07:23.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter