How to Stop all Pipeline tasks correctly

2019-04-16 10:44发布

问题:

how to stop Pipleline tasks correctly, I've tried but when i press Abort button i get an AV, i'm not too good at debugging,i have reached to DoOnStop(task); in OtlParallel then i couldn't figure out what to do next, i believe there is something missing ?

type
   procedure SetInProcess(const Value: Boolean);
private
   FInProcess: Boolean;
   property inProcess: Boolean read FInProcess write SetInProcess;
public
   FStopAll: Boolean;
   procedure FlushData;
   procedure Retriever(const input: TOmniValue; var output: TOmniValue);
  ...
  procedure TForm1.SetInProcess(const Value: Boolean);
  var
    I: Integer;
  begin
    if Value = InProcess then exit;
    memo1.ReadOnly := Value;
    FInProcess := Value;
    if Value then
     Memo1.Lines.Clear;
     Timer1.Enabled := Value;
     If not Value then
     begin
       FlushData;
       pipeline := nil;  
     end;
   end;

 procedure TForm1.Timer1Timer(Sender: TObject);
 begin
   If not InProcess then exit;
    FlushData;
   if Pipeline.Output.IsFinalized then
    InProcess := False;
   end; 
procedure TForm1.StartButton(Sender: TObject);
var
  i      : integer;
 urlList : TStrings;
 U, S    : string;
 value   : TOmniValue;
begin
  urlList := Memo2.Lines;
  pipeline := Parallel.Pipeline;

  pipeline.Stage(Retriver).NumTasks(StrToInt(Edit12.Text)).Run;

  for U in urlList do
   pipeline.Input.Add(U);
   pipeline.Input.CompleteAdding;
   inProcess := True;
 end;
procedure TForm1.FlushData;
var v: TOmniValue;
begin
  if pipeline = nil then exit;
  if pipeline.Output = nil then exit;

  Memo1.Lines.BeginUpdate;
  try
    while pipeline.Output.TryTake(v) do
    Memo1.Lines.Add(v.AsString);
    if FStopAll then
        begin
          Pipeline.Cancel;
        end;
    Memo1.Lines.EndUpdate;
 except
   on E: Exception do
   begin
     Memo1.Lines.Add(E.Message);
   end;
 end;
  Memo1.Lines.EndUpdate;      
end;

procedure TForm1.Retriver(const input: TOmniValue; var output: TOmniValue);
var
  lHTTP                 : TIdHTTP;
  Params                : TStrings;
  Reply,String1,String2 : string;
begin
  X      := Input.AsString;
  Params := TStringList.Create;
  string1   := Extract1(X);
  string2   := Extract2(X);;

  Params.Add('username=' + string1);
  Params.Add('password=' + string2);

  lHTTP := TIdHTTP.Create(nil);
  try
  ...
  Reply := lHTTP.Post('https://www.instagram.com/accounts/login/ajax/', Params);
    if AnsiContainsStr(Reply, 'no')
    then
    begin
      Alive.Add(string1+string2+' Client ok'); ///Alive is Global Var stringlist created earlier
    end;
  except
     on E: EIdHTTPProtocolException do       
         Exit
  end;
  lHTTP.Free;
end;
 procedure TForm1.AbortButton(Sender: TObject);
 begin
   try
     FStopAll := False;
   finally
     FStopAll := True;
   end;
 end;

回答1:

In your case of over-simplified one-stage pipeline suffice would be moving check into the worker stage itself.

procedure Retriever(const input: TOmniValue; var output: TOmniValue);
var 
  ....
begin
   if FStopAll then exit;
   X   := Input.AsString;
....

PS. I want to repeat that your code leaks memory badly, and that you ignored all my notes I stated before.

PPS. This code not also makes little sense (there is not point in flip-vloppign the variable to one value then to another) but is syntactically incorrect and would not compile. Thus it is not the same code you actually run. It is some different code.

procedure TForm1.AbortButton(Sender: TObject);
 begin
   try
     FStopAll := False;
   finally
     FStopAll := True;
   end;
 end;