Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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
1-1106909781
ORMADA
2005-01-28 13:56
2005.02.20
Как перебилдить dpk из командной строки ?


1-1107852549
Denis
2005-02-08 11:49
2005.02.20
Как проскроллить RichEdit до выделеного участка текста?


1-1107494504
cvg
2005-02-04 08:21
2005.02.20
Как задать фонту св-во Bold?


4-1104852362
Эдик
2005-01-04 18:26
2005.02.20
Как получить список модомов Win 95/98/2000/XP


14-1104829079
www.Vlad.uk
2005-01-04 11:57
2005.02.20
Винда требует диск...





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский