Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.02.20;
Скачать: CL | DM;

Вниз

Поток. Остановка и разрушение!   Найти похожие ветки 

 
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;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.052 c
4-1104940427
Fanny
2005-01-05 18:53
2005.02.20
Как узнать, есть ли права на запись в реестр?


14-1106819014
Ega23
2005-01-27 12:43
2005.02.20
Держите кулаки!


4-1104517983
Zahar
2004-12-31 21:33
2005.02.20
Программа дефрагментации диска


14-1107333696
vecna
2005-02-02 11:41
2005.02.20
Настройка Delphi


1-1107352137
MakedoneZ
2005-02-02 16:48
2005.02.20
Локальные переменные.