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

时间:2011-02-04 03:21:41

标签: multithreading delphi terminate

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

目前的代码如下: -

单击

启动线程
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; 

创建线程

constructor TCompareFilesThread.Create;
begin
  inherited Create(False);
end;

实际线程

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;

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

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

1 个答案:

答案 0 :(得分:5)

是的,在您的线程对象上调用Terminate。它将Terminated设置为true,这就是它所做的一切 - 您的线程需要检查Terminated,因为您的代码正在执行(尽管存在错误,请参阅下文。)

更详细地说:你在这里创建你的线程对象:

cmpfiles := TCompareFilesThread.Create();

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

if Assigned(cmpfiles) then begin
  cmpfiles.Terminate;
end;

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

FreeAndNil(cmpfiles);

Execute的最后执行,因为线程对象将被删除 - 您不希望再运行任何代码。

我发现了一个错误:您的Execute代码包含以下两个while循环:

while NOT eof(forg) do
begin
   while Terminated = False do
      begin
         ...
      end;
end;

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

while (not eof(forg) and not Terminated) do
begin
   ...
end;

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

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

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