![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как можно убить запущенный поток? [D7]
Rusa © (2004-08-18 07:41:00)Имею программу, которая запускает несколько потоков, производящих независимые подключения к базе данных Оракл и вызывающих там хранимую процедуру. Каждый поток передает на вход процедуры свои параметры. В среднем каждая процедура отрабатывает за 10 минут, поэтому я ее запуск выделяю в отдельный поток что-бы интерфейс программы не висел. Все нормально работает и выполняется, есть у меня только вот такой вопрос. Иногда надо бывает завершить работу программы до завершения выполнения хранимых процедур на сервере. Как правильно убить в таком случае мои запущенные потоки? В документации написано, что для того что-бы пользоваться методом TThread.Terminate надо в TThread.Execute постоянно проверять свойство Terminated и далее делать выводы о работе потока. У меня не получиться этого делать, т.к. после вызова метода ExecProc для хранимой процедуры я уже не смогу проверять никакие свойства, вплодь до ее завершения. Есть ли еще какие-нибудь способы в данной ситуации, что-бы убить потоки?
Привожу свой код:
Класс потока
unit thread;
interface
uses
Classes, DbTables, datamod, Windows, SysUtils, DB;
type
TOraThread = class( TThread )
private
protected
FDatabase: TDatabase;
FStoredProc: TStoredProc;
FSession: TSession;
procedure Execute; override;
public
FTownId: Byte;
FBillTypeId: Byte;
constructor Create( aReportDateId: Byte;
aReportDateId2: Byte;
aSysDate: TDateTime;
aBillTypeId: Byte;
aTownId: Byte;
aTruncateFlag: Byte );
end;
implementation
{ TOraThread }
procedure TOraThread.Execute;
begin
if Assigned( FStoredProc ) then
begin
FStoredProc.Close;
if not FStoredProc.Prepared then FStoredProc.Prepare;
FStoredProc.ExecProc;
InterlockedDecrement( thread_count );
FStoredProc.Close;
FStoredProc.Free;
FStoredProc := nil;
end;
if Assigned( FDatabase ) then
begin
FDatabase.Connected := False;
FDatabase.Free;
FDatabase := nil;
end;
if Assigned( FSession ) then
begin
FSession.Active := False;
FSession.Free;
FSession := nil;
end;
end;
constructor TOraThread.Create( aReportDateId: Byte;
aReportDateId2: Byte;
aSysDate: TDateTime;
aBillTypeId: Byte;
aTownId: Byte;
aTruncateFlag: Byte );
begin
inherited Create( True );
FTownId := aTownId;
FBillTypeId := aBillTypeId;
FSession := TSession.Create( dm );
with FSession do
begin
Active := False;
Name := 'Session' + IntToStr( thread_count );
KeepConnections := False;
SessionName := 'Session' + IntToStr( thread_count );
end;
FDatabase := TDatabase.Create( dm );
with FDatabase do
begin
Connected := False;
DatabaseName := 'DatabaseName' + IntToStr( thread_count );
Name := 'DatabaseName' + IntToStr( thread_count );
SessionName := 'Session' + IntToStr( thread_count );
KeepConnection := False;
LoginPrompt := False;
AliasName := dm.Database.AliasName;
Params.Clear;
Params.Add( 'user name' );
Params.Values[ 'user name' ] := username;
Params.Add( password );
Params.Values[ 'password' ] := password;
end;
FStoredProc := TStoredProc.Create( dm );
with FStoredProc do
begin
Active := False;
DatabaseName := 'DatabaseName' + IntToStr( thread_count );
Name := 'StoredProc' + IntToStr( thread_count );
StoredProcName := 'XXX.XXXXXXXXXXXXX';
SessionName := 'Session' + IntToStr( thread_count );
Params.Clear;
Params.CreateParam( ftSmallInt, 'p_report_date_id', ptInput );
Params.CreateParam( ftSmallInt, 'p_report_date_id2', ptInput );
Params.CreateParam( ftDate, 'p_sys_date', ptInput );
Params.CreateParam( ftSmallInt, 'p_bill_type_id', ptInput );
Params.CreateParam( ftSmallInt, 'p_town_id', ptInput );
Params.CreateParam( ftSmallInt, 'p_trc', ptInput );
ParamByName( 'p_report_date_id' ).AsSmallInt := aReportDateId;
ParamByName( 'p_report_date_id2' ).AsSmallInt := aReportDateId2;
ParamByName( 'p_sys_date' ).AsDate := aSysDate;
ParamByName( 'p_bill_type_id' ).AsSmallInt := aBillTypeId;
ParamByName( 'p_town_id' ).AsSmallInt := aTownId;
ParamByName( 'p_trc' ).AsSmallInt := aTruncateFlag;
end;
FDatabase.Connected := True;
end;
end.
Вызовы из основного модуля:
if KeepWorking = False then exit;
InterlockedIncrement( thread_count );
aThread := TOraThread.Create( report_date_id,
report_date_id2,
sys_date,
bill_type_id,
town_id,
trc );
ThreadList.Add( aThread );
aThread.Priority := tpNormal;
aThread.FreeOnTerminate := True;
aThread.OnTerminate := OnThreadFinished;
StatusBar1.SimpleText := 'Started ...';
aThread.Resume;
while (( thread_count <> 0 ) and
( thread_count >= StrToInt( fmOptions.meMaxThreadCount.Text ))) do
begin
Application.ProcessMessages;
Sleep( 350 );
end;
procedure TFormMain.OnThreadFinished( Sender: TObject );
var i: Byte;
begin
Memo.Lines.Add( 'Thread finished.' );
ThreadList.Remove( aThread );
end;
// Вот как я делаю принудительное закрытие на данный момент
// Terminate не дает нужного результата. Приходиться ждать
// завершения уже запущенных потоков
procedure TFormMain.tbExitClick(Sender: TObject);
begin
Memo.Lines.Add( 'Принудительное завершение' );
KeepWorking := False;
PostQuitMessage( 0 );
aThread := nil;
if Assigned( ThreadList ) then
begin
while ( ThreadList.Count > 0 ) do
begin
aThread := ThreadList.Last;
aThread.WaitFor;
if ( ThreadList.IndexOf( aThread ) <> -1 ) then ThreadList.Remove( aThread );
aThread := nil;
end;
end;
Close;
end;
P.S. Спасибо всем кто смог дочитать до конца мой вопрос :))
Evgeny V (2004-08-18 08:56:00) [1]TerminateThread, но не желательно без крайней необходимости.