终止线程,退出前运行代码

Fla*_*lyn 2 delphi multithreading terminate

我希望能够在点击按钮时终止一个线程,例如,如果用户需要,请将该过程停止一半.显然,你可以通过在线程中设置Terminated变量来实现这一点,这意味着你可以在退出之前执行某些代码而不是突然终止.

到目前为止的代码如下: -

单击启动线程

procedure TForm1.Panel29Click(Sender: TObject);
var
cmpfil : TThread;

begin
  if (Edit3.Text <> '') AND (Edit4.Text <> '') then
  begin
    Form1.ProgressBar1.Min := 0;
    Form1.Progressbar1.Max := 30000;
    Form1.ProgressBar1.Position := 0;
    cmpfiles := TCompareFilesThread.Create();
  end;
end; 
Run Code Online (Sandbox Code Playgroud)

创建线程

constructor TCompareFilesThread.Create;
begin
  inherited Create(False);
end;
Run Code Online (Sandbox Code Playgroud)

实际线程

procedure TCompareFilesThread.Execute;
var
  forg, fpat : file;
  byteorg, bytepat : Array[0..1023] of byte;
  i,z,o : integer;
  fil1,fil2 : TFilename;
begin
  //Form1.CompareFiles(FEdit3Text, FEdit4Text, FGrid, FOp, FProg);

  begin
    fil1 := Form1.Edit3.Text;
    fil2 := Form1.Edit4.Text;
    if Form1.CRCAdlerGenFile(fil1,1) <> Form1.CRCAdlerGenFile(fil2,1) then //Only Run if files arn't same
    begin
      op := 3;
      synchronize(SetOP);

      i := 0;
      x := 1;
      o := 0;

      AssignFile(forg,fil1);
      FileMode := fmOpenRead;
      Reset(forg,1);
      AssignFile(fpat,fil2);
      FileMode := fmOpenRead;
      Reset(fpat,1);

      //Set Progress Bar

      while NOT eof(forg) do
      begin
        while Terminated = False do
        begin
          BlockRead(forg,byteorg,1024);
          BlockRead(fpat,bytepat,1024);

          for z := 0 to 1023 do
          begin
            if byteorg[z] <> bytepat[z] then
            begin
              synchronize(sProgBarNext);
              by := bytepat[z];
              off := IntToStr(o);
              synchronize(SyncGrid);
              inc(x);
            end;
            inc(o);
          end;
        end;
      end;

      CloseFile(forg);
      CloseFile(fpat);
    end;
  end;
  Free;
end;
Run Code Online (Sandbox Code Playgroud)

我已经添加了While Terminated = False do一行,当更改时,该行将停止该过程.我似乎无法弄清楚如何改变它.我从未创造过那个变量; 它是内置的Delphi功能.我读过TMyThread.Terminate()但是我似乎无法确切地知道它的作用.它将Terminated设置为True还是只会杀死它所在的线程?

PS我还没有发布同步例程中的代码.一个打印到StringGrid,一个更新ProgressBar,第三个设置一个由StringGrid Sync例程使用的op变量,我没有看到这个代码与问题相关,但我可以发布请求.

Dav*_*vid 5

是的,在您的线程对象上调用Terminate.它设置Terminated为true,就是这样 - 你的线程需要检查Terminated,就像你的代码一样(尽管有一个bug,见下文.)

更详细:您在此处创建线程对象:

cmpfiles := TCompareFilesThread.Create();
Run Code Online (Sandbox Code Playgroud)

cmpfiles您的形式或其他类,而不是您的本地的成员变量Panel29Click的过程.nil在构造函数中初始化它.然后当您需要取消时,请致电:

if Assigned(cmpfiles) then begin
  cmpfiles.Terminate;
end;
Run Code Online (Sandbox Code Playgroud)

如果线程存在,则设置Terminated标志.(编辑:感谢Rob,他建议避免使用FreeOnTerminate.我建议首先使用它是不好的建议.)你的线程还需要在完成时通知你的主线程,就在执行结束时,这样你就可以了可以释放它.一种方法是使用Synchronize通知主线程,然后在传递给Synchronize您的方法的主线程中释放线程对象.

FreeAndNil(cmpfiles);
Run Code Online (Sandbox Code Playgroud)

这样做在最后Execute,因为线程对象将被删除-你不希望任何代码运行.

我发现的一个错误: 您的Execute代码具有以下两个while循环:

while NOT eof(forg) do
begin
   while Terminated = False do
      begin
         ...
      end;
end;
Run Code Online (Sandbox Code Playgroud)

这实际上是在没有终止的情况下循环,它只会检查文件末尾Terminated是否设置为true.您可能希望循环同时检查两个条件,例如:

while (not eof(forg) and not Terminated) do
begin
   ...
end;
Run Code Online (Sandbox Code Playgroud)

哦,另一个错误,你的线程代码访问Form1的数据:

if Form1.CRCAdlerGenFile(fil1,1) <> Form1.CRCAdlerGenFile(fil2,1) then //Only Run if files arn't same
Run Code Online (Sandbox Code Playgroud)

这段代码是什么,在文件上运行CRC?如果CRCAdlerGenFile函数实际上没有触及Form1的任何部分,并且它只依赖于它的参数(并且它们是独立的),那么将它作为辅助函数在某处 - 它不必是类的一部分,你可以拥有独立功能.如果它依赖于Form1的部分,则不应该从您的线程代码中调用它.