Форум: "Основная";
Текущий архив: 2005.02.20;
Скачать: [xml.tar.bz2];
ВнизПоток. Остановка и разрушение! Найти похожие ветки
← →
Gek1 (2005-02-03 15:37) [0]Мастера, что-то я запутался совсем! Помогите разобраться с правильной остановкой потока!
Суть такая: в потоке я использую cкриптовый язык Pascal Script
С главной формы я должен уметь запускать и останавливать поток!
Также при закрытии формы должен правильно отработать метод Free потока!
У меня же после остановки и заново запуска потока - скрипт продолжал работать не с начала а с того места где он остановился! Так как скрипт я использую в отдельном потоке и управляю им с формы - мне надо послать команду скрипту на остановку и подождать пока он дейсвительно остановиться.
А также мне надо предусмотреть остановку скрипта перед Destroy
Вот что у меня получилось:
type
TScriptThread = class(TThread)
private
{ Private declarations }
procedure OnLine(Sender: TObject);
procedure IFPS3ClassesPlugin1CompImport(Sender: TObject; x: TPSPascalCompiler);
procedure IFPS3ClassesPlugin1ExecImport(Sender: TObject; Exec: TPSExec; x: TPSRuntimeClassImporter);
procedure PSScriptCompile(Sender: TPSScript);
procedure PSScriptExecute(Sender: TPSScript);
procedure ExecuteScript;
protected
{ Protected declarations }
procedure Execute; override;
public
{ Public declarations }
constructor Create(Sender : TObject);
destructor Destroy; override;
procedure LoadMacros(Script : TStringList);
procedure Start;
procedure Stop;
end;
implementation
uses main;
var
Thread : TScriptThread;
Macros : TStringList;
Started : Boolean;
Just_Stoped : Boolean;
PSScript: TPSScript;
constructor TScriptThread.Create(Sender : TObject);
begin
inherited Create(True); {Поток создаем в состоянии «Приостановлен»}
FreeOnTerminate := True; {Поток освободит ресурсы при окончании работы}
{Переменные}
Thread := Self;
Macros:=TStringList.Create;
Started := false;
Just_Stoped := false;
{Script}
PSScript := TPSScript.Create(nil);
PSScript.OnCompile := Thread.PSScriptCompile;
PSScript.OnCompImport := Thread.IFPS3ClassesPlugin1CompImport;
PSScript.OnExecImport := Thread.IFPS3ClassesPlugin1ExecImport;
PSScript.OnExecute := Thread.PSScriptExecute;
PSScript.OnLine := Thread.OnLine;
Self.Priority := tpNormal; {Стартуем с нормальным приоритетом}
end;
destructor TScriptThread.Destroy;
begin
if PSScript.Running then PSScript.Stop;
while PSScript.Running do
begin
sleep(10);
end;
PSScript.Free;
Macros.Free;
inherited Destroy;
end;
procedure TScriptThread.LoadMacros(Script : TStringList);
begin
if not Assigned(Macros) then Exit;
if Script.Count <=0 then Exit;
if Started then Exit;
Macros.Clear;
Macros.AddStrings(Script);
end;
procedure TScriptThread.Start;
begin
if not Assigned(Macros) then Exit;
if Macros.Count <=0 then Exit;
if Started then Exit;
Started := true;
Resume; {Переводим поток в состояние «Активен»}
end;
procedure TScriptThread.Stop;
begin
if not Started then Exit;
Started := false;
if PSScript.Running then PSScript.Stop;
Just_Stoped := true;
while PSScript.Running or (not Just_Stoped) do
begin
sleep(10);
end;
Suspend; {Переводим поток в состояние «Остановлен»}
end;
procedure TScriptThread.Execute;
begin
while not Terminated do
begin
if Started then
begin
ExecuteScript;
if Just_Stoped then Just_Stoped := false
else Stop;
end
else sleep(500); //ждем примерно пол секунды
end;
end;
Также скрипт перед каждым выполнением строки генерирует событие Online! Там я встроил специально маленкую задержу, чтоб регулировать скорость скрипта:procedure TScriptThread.OnLine(Sender: TObject);
begin
sleep(50);
end;
Думал уже в Online проверять не остановлен ли и останавливать здесь именно!
Сам Скрипт останавливаеться только PSScript.Stop.
Suspend приостанавливает поток и после Resume скрипт продолжает выполняться как будто ничего и небыло!
Мастера как мне предусмотреть правильную остановку скрипта c формы и как предусмотреть корректное разрушение потока (Скрипт как я понял надо остановить а потом вызвать PSScript.Free).
← →
Digitman © (2005-02-03 16:05) [1]
> Suspend приостанавливает поток и после Resume скрипт продолжает
> выполняться как будто ничего и небыло
а ничего и не было !
так и должно быть - suspend приостанавливает работу потока, а resume возобновляет именно с той точки, где поток был приостановлен предыдущим вызовом suspend
а где реализация метода ExecuteScript ?
← →
Gek1 (2005-02-03 16:38) [2]
> а где реализация метода ExecuteScript ?
procedure TScriptThread.ExecuteScript;
procedure OutputMessages;
var
l: Longint;
b: Boolean;
begin
b := False;
for l := 0 to PSScript.CompilerMessageCount - 1 do
begin
AddToDebug("Compiler: "+ PSScript.CompilerErrorToStr(l));
end;
end;
begin
PSScript.Script.Assign(Macros);
AddToDebug("Compiling");
if PSScript.Compile then
begin
OutputMessages;
AddToDebug("Compiled succesfully");
if not PSScript.Execute then
begin
AddToDebug(PSScript.ExecErrorToString +" at "+Inttostr(PSScript.ExecErrorProcNo)+"."+Inttostr(PSScript.ExecErrorByteCodePosition));
end else AddToDebug("Succesfully executed");
end else
begin
OutputMessages;
AddToDebug("Compiling failed");
end;
end;
скрипт запускаеться в том же самом дополнительном потоке...
← →
Digitman © (2005-02-03 16:55) [3]ясно.
объкт PSScript имеет какие-то методы/св-ва для немедленного корректного прерывания компиляции/импорта/исполнения скрипта ?
если да, то используй их в обработчикках всех событий объекта PSScript .. в обработчике первым делом проверяй устанавливаемы извне флаг прерывания исполнения тек.макроса, и если он взведен, то тут же командуй объекту PSScript прервать начатую работу
← →
Gek1 (2005-02-03 17:01) [4]
> Digitman © (03.02.05 16:55) [3]
Так получиться когда я хочу остановить скрипт! а что делать в методе TScriptThread.Destroy? Там мне сначала надо установить внешний флаг остановки, а потом както подождать пока он дейсвительно завершиться!..... как это мне правильно сделать?
← →
Digitman © (2005-02-03 17:06) [5]
> что делать в методе TScriptThread.Destroy? Там мне сначала
> надо установить внешний флаг остановки
да.
а следом - inherited
inherited взведет флаг Terminated, а ты его так же контролируешь в цикле в теле Execute на предмет выхода из цикла и нормального завершения Execute
ну и последим делом в деструкторе - разрушение объекта PSScript
← →
Gek1 (2005-02-03 17:20) [6]т.е
1.устанавливаю флаг
2.inherited Destroy;
3.PSScript.Free;
Macros.Free;
или как?
← →
Digitman © (2005-02-03 17:29) [7]
> Gek1 (03.02.05 17:20) [6]
примерно так
но я бы создавал/разрушал объекты PSScript и Macros не в конструкторе/деструкторе, а непосредственно в Execute (что логичней)
тело Execute:
try
1.Конструируем PSScript
2.Конструируем Macros
while not Terminated do
чего-то там
finally
1.рзрушаем PSScript, если создан
2.рзрушаем Macros, если создан
end;
except
//протокол непредвиденных искл-ний
end;
← →
Gek1 (2005-02-03 17:47) [8]
> Digitman © (03.02.05 17:29) [7]
да похоже что так логичнее... но мне непонятно тогда как мне останавливать скрипт и заново запускать! При этом перед каждым запуском я должен заново его откомпилировать. т.е в промежутке должно отрабатывать метод LoadMacros.
← →
Digitman © (2005-02-03 17:52) [9]
> LoadMacros
этот метод так же может взводить флаг останова ранее стартованной интерпретации
взведя этот флаг метод дожидается факта реального останова и грузит новый макрос
← →
Gek1 (2005-02-04 10:02) [10]У меня еще такой вопрос:
Вот я в методе TScriptThread.Start использую переменную Started и в самом доп. потоке я ее тоже использую! Метод Start вызываеться с основного потока. При этом, как мне кажеться, надо защитить потоко опасную переменную Started. Или же нет?
Что лучше в этом случае сделать?
← →
Digitman © (2005-02-04 10:35) [11]Boolean-значения - однобайтные, защищать их в общем случае не обязательно.
Обрати внимание, что Борланд не защищает флаг TThread.FTerminated, хотя этот флаг как правило используется по записи (метод Terminate) и чтению (св-во Terminated) более чем одним кодовым потоком - например, доп.поток в цикле читает значение (и если он взведен, немедленно выходит из цикла) флага, а осн.поток взводит этот флаг в деструкторе доп.потока
← →
Gek1 (2005-02-04 12:04) [12]Еще такой вопрос:
Вот например надо чтобы при окончании макроса поток завершился и овободил ресурсы!
в методе Execute я просто должен убрать while not Terminated do
а вот метод Destroy вызовется сам после окончания метода Execute или же надо вызывать в доп. потоке вручную?
← →
Eraser © (2005-02-04 12:17) [13]Gek1
Destroy вызовется сам после окончания метода Execute
Да, если установлен флаг FreeOnTerminate.
Digitman
Boolean-значения - однобайтные, защищать их в общем случае не обязательно.
А вот это интересно, а какие переменные надо защиать? Стоки- это понятно. А переменные какой-либо фиксированной длины?
← →
Digitman © (2005-02-04 12:29) [14]
> Gek1 (04.02.05 12:04) [12]
> в методе Execute я просто должен убрать while not Terminated
> do
это как ?
вообще-то никто не напрягает тебя использовать цикл... хоть в таком хоть в ином виде ..
> надо чтобы при окончании макроса поток завершился и овободил
> ресурсы!
да, знаешь ли, сие крайне желательно) .. и что у тебя этому мешает ?
> а вот метод Destroy вызовется сам после окончания метода
> Execute или же надо вызывать в доп. потоке вручную?
не надо его вызывать "вручную".
на то есть св-во FreeOnTerminate
> Eraser © (04.02.05 12:17) [13]
> А вот это интересно, а какие переменные надо защиать? Стоки-
> это понятно. А переменные какой-либо фиксированной длины?
как минимум - переменные, имеющие размер более одного байта.
← →
Eraser © (2005-02-04 12:34) [15]Странно, мне всегда казалось, что защищать надо любые переменные...
Чем однобайтовая переменная хуже 2-х байтовой?
← →
Digitman © (2005-02-04 12:46) [16]
> Eraser © (04.02.05 12:34) [15]
> Чем однобайтовая переменная хуже 2-х байтовой?
наоборот - лучше)
о защите одного байта в физ.памяти от одновременных попыток модификации заботятся аппаратные арбитры.
← →
Eraser © (2005-02-04 12:50) [17]Digitman ©
Буду иметь ввиду ))
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2005.02.20;
Скачать: [xml.tar.bz2];
Память: 0.51 MB
Время: 0.035 c