我希望能够在点击按钮时终止一个帖子,例如,如果用户需要,请将该过程停止一半。显然,你可以通过在线程中为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变量,我没有看到这个代码与问题相关,但我可以发布请求。
答案 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的部分,则不应该从您的线程代码中调用它。