Экспертная система Delphi.int.ru

Сообщество программистов
Общение, помощь, обмен опытом

Логин:
Пароль:
Регистрация | Забыли пароль?

Delphi.int.ru Expert

Другие разделы портала

Переход к вопросу:

#   

Статистика за сегодня:  


Лучшие эксперты

Подробнее »



Вопрос # 6 119

/ вопрос решён /

Здравствуйте!
Подскажите, пожалуйста как завершить поток во время работы при закрытии формы.

К вопросу прикреплён файл. Загрузить » (срок хранения: 60 дней с момента отправки вопроса)

Приложение:
  1. {{code|delphi}}...
  2. var
  3. Form1: TForm1;
  4. DownLoader_Thread: TDownLoader_Thread;
  5. CriticalSection: TCriticalSection;
  6.  
  7. implementation
  8.  
  9. {$R *.dfm}
  10.  
  11. procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
  12. var
  13. ThreadDieCode: Integer;
  14. begin
  15.  
  16. DownLoader_Thread.Terminate;
  17.  
  18.  
  19. ThreadDieCode := DownLoader_Thread.WaitFor;
  20.  
  21.  
  22. DownLoader_Thread.Free;
  23.  
  24. {SLRepairFiles.Free;
  25. CriticalSection.Free;}
  26. end;
  27.  
  28. procedure TForm1.FormCreate(Sender: TObject);
  29. begin
  30. SLRepairFiles := TStringList.Create;
  31. CriticalSection := TCriticalSection.Create;
  32.  
  33. SLRepairFiles.Add('Files\1.bmp');
  34. SLRepairFiles.Add('Files\1.docx');
  35. SLRepairFiles.Add('Files\1.mp4');
  36. SLRepairFiles.Add('Files\1.rar');
  37. SLRepairFiles.Add('Files\1.txt');
  38. end;
  39.  
  40. procedure TForm1.Button1Click(Sender: TObject);
  41. begin
  42. ProgressBar1.Max := SLRepairFiles.Count;
  43.  
  44. DownLoader_Thread := TDownLoader_Thread.Create(True);
  45. DownLoader_Thread.FSLRepairFiles := SLRepairFiles;
  46. DownLoader_Thread.FreeOnTerminate := True;
  47. DownLoader_Thread.Resume;
  48. end;
  49.  
  50. procedure TDownLoader_Thread.Execute;
  51. var
  52. HTTP: TIdHTTP;
  53. FS: TFileStream;
  54. i: Integer;
  55. Folder: string;
  56. begin
  57. HTTP := TIdHTTP.Create(nil);
  58.  
  59. CriticalSection.Enter;
  60.  
  61. for i := 0 to FSLRepairFiles.Count - 1 do
  62. begin
  63.  
  64.  
  65. if Self.Terminated then Break;
  66.  
  67. Folder := ExtractFilePath(Application.ExeName) + ExtractFilePath(FSLRepairFiles.Strings[i]);
  68. ForceDirectories(Folder);
  69. try
  70. try
  71. FS := TFileStream.Create(Folder + ExtractFileName(FSLRepairFiles.Strings[i]), fmCreate);
  72. HTTP.Get('http://77.108.194.247/' + StringReplace(FSLRepairFiles.Strings[i], '\', '/', [rfReplaceAll, rfIgnoreCase]), FS);
  73. except
  74. end;
  75. finally
  76. FS.Free;
  77. end;
  78.  
  79. Progress := i + 1;
  80.  
  81. Synchronize(SyncProc);
  82. end;
  83.  
  84. CriticalSection.Leave;
  85.  
  86. HTTP.Free;
  87. end;
  88.  
  89. procedure TDownLoader_Thread.SyncProc;
  90. begin
  91. Form1.ProgressBar1.Position := Progress;
  92.  
  93. end;{{code}}
  94.  
  95. {{code|delphi}}ThreadDieCode := DownLoader_Thread.WaitFor;{{code}}
  96.  
  97. {{code|delphi}}if Self.Terminated then Break;{{code}}
  98.  


Shouldercannon Вопрос решён, но можно продолжить его обсуждение в мини-форуме

Вопрос задал: Shouldercannon (статус: Посетитель)
Вопрос отправлен: 7 мая 2012, 10:45
Состояние вопроса: решён, ответов: 1.

Ответ #1. Отвечает эксперт: Вадим К

Здравствуйте, Shouldercannon!
Есть два способа - правильное завершение и завершение с извращением. Второй способ подразумевает убивания потока, но при этом убивают его "зверски" и никто не гарантирует, что основная программа выживет. Поэтому этот способ не рекомендуется. (выглядит он так

TerminateThread(имя_потока.ThreadId);
)

Правильный способ заключается в том, что поток должен сам завершить себя. Для этого у делфовской реализации потоков есть поле Terminated. Поток должен время от времени проверять это поле на true и если это так, то должен завершать свою работу (в общем случае - просто подчистить свои ресурсы и вызвать exit).

А тот, кому нужно, что бы поток завершился, просто вызывает
имя_потока.Terminate;
. Но никто не гарантирует, что поток сразу завершится (потоку туда ещё нужно дойти, проверить условие, завершиться). Если нужно дождаться завершения потока, то пишем так
имя_потока.Terminate;
имя_потока.WaitFor();
Но только нужно понимать, что WaitFor - блокирующая операция и будет подтормаживать интерфейс (но если поток завершится быстро, то никаких проблем).

Ответ отправил: Вадим К (статус: Академик)
Время отправки: 7 мая 2012, 11:06


Мини-форум вопроса

Всего сообщений: 3; последнее сообщение — 9 мая 2012, 09:30; участников в обсуждении: 2.
Shouldercannon

Shouldercannon (статус: Посетитель), 7 мая 2012, 14:04 [#1]:

Предпочтительнее правильное завершение.
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;
Снова тажа ошибка. Что-то я упустил, но что?
Вадим К

Вадим К (статус: Академик), 7 мая 2012, 19:00 [#2]:

Выставлили DownLoader_Thread.FreeOnTerminate := True; ? тогда вызывать деструктор для треда уже не нужно. Потому что делфи сама его вызовет за вас. А так как есть вызов WaitFor, то к моменту вызова деструктора Вами, он уже будет вызван.

К тому же, есть одна тонкая специфика. Если задано FreeOnTerminate := True, то OnTerminate треда вызывается в контексте потока. А если false, то в контексте треда, который вызвал free.
Галочка "подтверждения прочтения" - вселенское зло.
Shouldercannon

Shouldercannon (статус: Посетитель), 9 мая 2012, 09:30 [#3]:

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;

11 мая 2012, 16:10: Статус вопроса изменён на решённый (изменил модератор DNK)

Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.

Версия движка: 2.6+ (26.01.2011)
Текущее время: 22 февраля 2025, 11:45
Выполнено за 0.04 сек.