Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 06.05.2012, 17:18   #1
Shouldercannon
Участник клуба Подтвердите свой е-майл
 
Аватар для Shouldercannon
 
Регистрация: 26.01.2008
Сообщений: 1,897
Вопрос Завершить работу потока при закрытии формы

Код:
procedure TForm1.BStartClick(Sender: TObject);
begin
  ProgressBar1.Max := SLRepairFiles.Count;

  DownLoader_Thread := TDownLoader_Thread.Create(True);
  DownLoader_Thread.FSLRepairFiles := SLRepairFiles;
  DownLoader_Thread.FreeOnTerminate := True;
  DownLoader_Thread.Resume;
end;

procedure TDownLoader_Thread.Execute;
var
  HTTP: TIdHTTP;
  FS: TFileStream;
  i: Integer;
  Folder: string;
begin
  HTTP := TIdHTTP.Create(nil);

  CriticalSection.Enter;

  for i := 0 to FSLRepairFiles.Count - 1 do
  begin
    if Self.Terminated then Break; // Если главный поток приказал - умираем

    Folder := ExtractFilePath(Application.ExeName) + ExtractFilePath(FSLRepairFiles.Strings[i]);
    ForceDirectories(Folder);
    try
      try
        FS := TFileStream.Create(Folder + ExtractFileName(FSLRepairFiles.Strings[i]), fmCreate);
        HTTP.Get('http://77.108.194.247/' + FSLRepairFiles.Strings[i], FS);
      except
      end;
    finally
      FS.Free;
    end;

    Progress := i + 1;

    Synchronize(SyncProc);
  end;

  CriticalSection.Leave;

  HTTP.Free;
end;

procedure TDownLoader_Thread.SyncProc;
begin
  Form1.ProgressBar1.Position := Progress;
  if FSLRepairFiles.Count = Progress then Form1.Caption := 'Восстановлено: ' + IntToStr(FSLRepairFiles.Count) + ' файлов';
end;

procedure TForm1.BStopClick(Sender: TObject);
begin
  DownLoader_Thread.Terminate;
  DownLoader_Thread.WaitFor; // Ждём, когда DownLoader_Thread "мирно" помрёт
  DownLoader_Thread.Free;
end;
Где моя ошибка?
Изображения
Тип файла: gif Error.gif (7.9 Кб, 125 просмотров)

Последний раз редактировалось Shouldercannon; 07.05.2012 в 14:13.
Shouldercannon вне форума Ответить с цитированием
Старый 08.05.2012, 11:07   #2
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

Если вызываете WaitFor, то эта строчка ошибочна:
Код:
  DownLoader_Thread.FreeOnTerminate := True;
Нужно поставить в False.
"ковыряю изнутри" (с)
3D Hunter вне форума Ответить с цитированием
Старый 08.05.2012, 19:39   #3
Shouldercannon
Участник клуба Подтвердите свой е-майл
 
Аватар для Shouldercannon
 
Регистрация: 26.01.2008
Сообщений: 1,897
По умолчанию

Эксперементировал над этим кодом
Код:
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Test_Thread.Terminate;
  //CriticalSection.Free; // Вызивает ошибку: Неверный дескриптор (6). Нужно дождаться завершения работы потока для совершения этого действия
end;

procedure TForm2.FormShow(Sender: TObject);
begin
  CriticalSection := TCriticalSection.Create;

  Test_Thread := TTest_Thread.Create(True);
  Test_Thread.FreeOnTerminate := True;
  Test_Thread.Resume;
end;

procedure TTest_Thread.Execute;
var
  i: Integer;
begin
  CriticalSection.Enter;

  for i := 0 to 100 do
  begin
    if Self.Terminated then Break;
    Sleep(100);
    s := IntToStr(i);
    Synchronize(SyncProc);
  end;

  CriticalSection.Enter;
end;

procedure TTest_Thread.SyncProc;
begin
  Form2.Caption := s;
end;
поток останавливается нормально без ошибок, но возможно не уничтожается, но при этом я не могу уничтожить критическую секцию.
Shouldercannon вне форума Ответить с цитированием
Старый 08.05.2012, 19:52   #4
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

Ну вот скажите, а почему бы критическую секцию не поместить в сам поток? Переопределите класс, добавьте в protected все что ему нужно для работы, абстрагируйте логику, опишите конструктор и деструктор по-человечески. Поверьте, станет сразу проще думать, ошибок глупых не будет.

А теперь по коду.
И сразу ошибка-опечатка: дважды вызываете в Execute CriticalSection.Enter; Во-вторых, критическая секция может быть использована ранее, чем уничтожится поток, т.к. метод Terminate устанавливает свойство terminated в true.
Ну, чтобы ваш код работал, нужно подправить так:
Код:
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Test_Thread.Terminate;
  Test_Thread.WaitFor;
  CriticalSection.Free; // ошибки не будет
end;

procedure TForm2.FormShow(Sender: TObject);
begin
  CriticalSection := TCriticalSection.Create;

  Test_Thread := TTest_Thread.Create(True);
  Test_Thread.FreeOnTerminate := False;
  Test_Thread.Resume;
end;

procedure TTest_Thread.Execute;
var
  i: Integer;
begin
  CriticalSection.Enter;
  for i := 0 to 100 do
  begin
    if Self.Terminated then Break;
    Sleep(100);
    s := IntToStr(i);
    Synchronize(SyncProc);
  end;
  CriticalSection.Leave;
end;
"ковыряю изнутри" (с)
3D Hunter вне форума Ответить с цитированием
Старый 08.05.2012, 21:14   #5
Shouldercannon
Участник клуба Подтвердите свой е-майл
 
Аватар для Shouldercannon
 
Регистрация: 26.01.2008
Сообщений: 1,897
По умолчанию

Хочу уточнить.
1. При данной конструкции потока и способа его вызова критическая секция вовсе не нужна или я ошибаюсь? Поток ведь создаётся один раз при событии FormShow.
2. Так как поток теперь не уничтожается после выполнения своей задачи (Test_Thread.FreeOnTerminate := False;), то он будет "жить" до тех пор, пока не будет закрыта форма?

Последний раз редактировалось Shouldercannon; 08.05.2012 в 21:17.
Shouldercannon вне форума Ответить с цитированием
Старый 08.05.2012, 22:32   #6
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

1. Если нет разделяемых ресурсов, смысл от критической секции нулевой. Просто лишний объект. Однако, если переменная s (видимо, она глобальная) используется где-то еще, то тогда критическая секция нужна.
2. Да, поток будет жить и работать 10000 мс, судя по циклу в Execute. Деструктор потока нужно будет вызывать вручную, см. выше событие FormClose в моем посте.

Я бы посоветовал переменную s внести в класс потока, там с ней оперировать. Лучше стремиться к изоляции логики, а не размазывать ее по всем классам в коде.
P.S. Работу с критическими секциями и любыми объектами синхронизации с парной структурой вызова лучше оформлять в блок try..finally для безопасности и надежности.
"ковыряю изнутри" (с)

Последний раз редактировалось 3D Hunter; 08.05.2012 в 22:35.
3D Hunter вне форума Ответить с цитированием
Старый 08.05.2012, 22:49   #7
Shouldercannon
Участник клуба Подтвердите свой е-майл
 
Аватар для Shouldercannon
 
Регистрация: 26.01.2008
Сообщений: 1,897
По умолчанию

Цитата:
Я бы посоветовал переменную s внести в класс потока, там с ней оперировать. Лучше стремиться к изоляции логики, а не размазывать ее по всем классам в коде.
Переменная s изначально была в поле потока.
Код:
type
  // Поток для загрузки файлов
  TTest_Thread = class(TThread)
  private
    { Private declarations }
    s: string;
  protected
    procedure Execute; override;
    procedure SyncProc;
  public
  end;
Shouldercannon вне форума Ответить с цитированием
Старый 09.05.2012, 09:20   #8
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

Тогда отлично заработало у вас?
"ковыряю изнутри" (с)
3D Hunter вне форума Ответить с цитированием
Старый 09.05.2012, 09:30   #9
Shouldercannon
Участник клуба Подтвердите свой е-майл
 
Аватар для Shouldercannon
 
Регистрация: 26.01.2008
Сообщений: 1,897
По умолчанию

Цитата:
Сообщение от 3D Hunter Посмотреть сообщение
Тогда отлично заработало у вас?
Всё нормально.
Shouldercannon вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Как выскочить из цикла for при закрытии формы? men232 Общие вопросы Delphi 16 08.10.2011 13:16
ошибка при закрытии формы TotKtoNado Общие вопросы Delphi 3 03.07.2011 19:20
при закрытии потока(Tthread) посылать на форму код ответа или сообщение Человек_Борща Общие вопросы Delphi 2 14.12.2010 21:19
запуск процесса при закрытии формы RUSlan48 Общие вопросы Delphi 3 29.03.2010 21:49
Сворачивание в трей при закрытии формы xxxsas Общие вопросы C/C++ 0 22.01.2009 08:11