|
Вопрос # 6 119/ вопрос решён / |
|
Здравствуйте!
Подскажите, пожалуйста как завершить поток во время работы при закрытии формы.
К вопросу прикреплён файл. Загрузить » (срок хранения: 60 дней с момента отправки вопроса)
Приложение: Переключить в обычный режим- {{code|delphi}}...
- var
- Form1: TForm1;
- DownLoader_Thread: TDownLoader_Thread;
- CriticalSection: TCriticalSection;
-
- implementation
-
- {$R *.dfm}
-
- procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
- var
- ThreadDieCode: Integer;
- begin
-
- DownLoader_Thread.Terminate;
-
-
- ThreadDieCode := DownLoader_Thread.WaitFor;
-
-
- DownLoader_Thread.Free;
-
- {SLRepairFiles.Free;
- CriticalSection.Free;}
- end;
-
- procedure TForm1.FormCreate(Sender: TObject);
- begin
- SLRepairFiles := TStringList.Create;
- CriticalSection := TCriticalSection.Create;
-
- SLRepairFiles.Add('Files\1.bmp');
- SLRepairFiles.Add('Files\1.docx');
- SLRepairFiles.Add('Files\1.mp4');
- SLRepairFiles.Add('Files\1.rar');
- SLRepairFiles.Add('Files\1.txt');
- end;
-
- procedure TForm1.Button1Click(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/' + StringReplace(FSLRepairFiles.Strings[i], '\', '/',
[rfReplaceAll, rfIgnoreCase]), 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;
-
- end;{{code}}
-
- {{code|delphi}}ThreadDieCode := DownLoader_Thread.WaitFor;{{code}}
-
- {{code|delphi}}if Self.Terminated then Break;{{code}}
-
 |
Вопрос задал: 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 (статус: Посетитель), 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 (статус: Посетитель), 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)
Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.
|