OnTerminate事件中不能释放线程???!!!难道书上有错?bug?(100分)

  • 主题发起人 主题发起人 PYH
  • 开始时间 开始时间
P

PYH

Unregistered / Unconfirmed
GUEST, unregistred user!
 TThread类属性FreeOnTerminate,按帮助文件上的说法(很多参考书上也是这样)
,为false时线程对象可以在OnTerminated事件中释放,我的程序代码如下:
主Form很简单,test为自定义的线程类
type
TForm1 = class(TForm)
Button1: TButton;
{创建2个线程}
Button2: TButton;
{释放线程1}
Button3: TButton;
{释放线程2}

procedure Button1Click(Sender: TObject);

procedure tern1(Sender:TObject);
{线程1 Onterminate事件}
procedure tern2(Sender:TObject);
{线程2 Onterminate事件}

procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);

public
{ Public declarations }
end;

var
Form1: TForm1;
implementation
uses Unit2;
var
th1:test;{线程对象}
th2:test;
{$R *.DFM}
{Button1创建两个线程,并设置了Onterminate事件}
procedure TForm1.Button1Click(Sender: TObject);
begin
if th1 = nil then
begin

th1:=test.Create(true);
th1.OnTerminate:=tern1;
th1.FreeOnTerminate:=false;
th1.Resume;
end;
if th2 = nil then
begin

th2:=test.Create(true);
th2.OnTerminate:=tern2;
th2.FreeOnTerminate:=false;
th2.Resume;
end;
end;

{线程1 Onterminate事件,显式释放线程}
procedure TForm1.tern1(Sender: TObject);
begin
if th1<>nil then
begin
th1.Free;
th1:=nil;
beep;
end;
end;
{线程2 Ontermiante事件}
procedure TForm1.tern2(Sender: TObject);
begin
if th2<>nil then
begin
th2.Free;
th2:=nil;
beep;
end;
end;

{button2结束线程1}
procedure TForm1.Button2Click(Sender: TObject);
begin
if th1<>nil then
th1.Terminate;
end;


{button3结束线程2}
procedure TForm1.Button3Click(Sender: TObject);
begin
if th2<>nil then
th2.Terminate;
end;

end.

unit2
{线程也很简单,除了一个循环,什么也没做}
type
test = class(TThread)
private
buf1:array[0..8191] of integer;
buf2:array[0..8191] of integer;
{这二个buffer,似乎有魔力}
protected
procedure Execute;
override;
end;

implementation
 
procedure test.Execute;
 
begin
while not Terminateddo
begin
end;
  
end;
end.

  运行以上代码,创建线程没问题,结束线程时,第一个正常,结束第二个线程时出
错,是个win32错误,code 为5, 奇怪的是如果将线程中的二个8k大的Buffer去掉,则
一切正常;难道不能在OnTerminate事件中释放线程对象,难道buffer 不能太大,难道
书上说错了!!

使用Freeandnil和先调用对象的free方法,再将其赋成nil,有何不同!!
另:如果先释放第二个线程,再释放第一个线程,也没问题,太怪了!。
   困扰多日,请不吝赐教,先谢了!


--------------------------------------------------------------------------------

 
th1:=test.create(true);
th2:=test.Create(true);
你的线程还没唤醒就terminate似乎不妥吧
线程的terminate我见过的都是在execute过程中
 
请看delphi help的这段描述:
For Terminate to work, the thread's Execute method and any methods
that Execute calls should check Terminated periodically and exit when
it's True.
注意 the thread's Execute method and any methods that Execute calls
你的线程没唤醒,故无法执行execute;当然也就无法terminate
换成th1:=test.create(false);
th2:=test.Create(false);
试试
 
老兄,你太粗心了!!
请再仔细看看代码。如果没唤醒怎会出现释放问题!!
 
不好意思,没看清楚
没办法,等待能人吧
 
不能在thread对象的onterminate事件(包括任何事件)中释放对象本身。
 
fishheand:

你看过帮助文件吗?delphi5开发人员指南中也提过,OnTerminate事件中
可以释放线程对象。你认为书上有错?如果把线程对象中的二个buffer去掉,则
未发生过释放问题,你认为是巧合??!!!
你的那个说法来自那本大作?
 
同意fu_xiang_yu和PYH的意见,补充一点,create(true)后线程就开始执行了,
之后的程序可能都没被执行。
 
to Junior :
你看代码了吗?你写过 TThread的程序吗?
你知道Create(true)的true是什么意思吗?
 
to pazee
sorry!我把true和false的意思弄反了(无地自容)。。。^0^
 
线程行为一定要以良好的方式结束,即让其自然结束,
不然人家还未完成工作就被你剪掉脐带是很麻烦的,
所以我觉得你在FREE 和NIL之前必须调用WAITFOR过程
等待线程告诉你'我好了',才能继续FREE ...
当然若线程结束得够快,这个错误就会被掩盖过去.
所以你把BUFFER去掉就好象正常了
 
waitfor 我也试过,一样出错!其实线程的free 本身就回调用waitfor过程;
各位,对你门的热情表示感谢!
这段代码很简单,请热心大虾们先试一下,再给一个答案,哪怕发现新的问题,也算找
到知音了。
 
>>OnTerminate事件中不能释放线程???!!!难道书上有错?
OnTerminate事件中不能释放线程!!!确实书上有错! :-)
这一点Delphi BugList有介绍,由于terminate的过程所致,
释放线程并不安全,Help/书都犯了错误。
这种错误并非总出现,就象你上面的例子那样。
ps:提供一个思考方法,其实有编程经验的也都知道:
遇到“似乎有魔力”的问题,99.99%是访问了没初始化/被释放的内存带来的。
 
我同意温柔一刀的说法,你试下先释放的内存吧
 
尽管在进程终止时会自动清除所有的线程对象,
但及时清除不再用的线程对象,会提高内存的使用效率,
将FreeOnTerminate属性设置为True:
这样当一个线程终止时就会触发onterminate事件,
从而在事件处理过程内清除线程对象。
 
同意温柔一刀的说法,我试过在BUFFER小到某一尺寸时就正常了,约是38XX字节,
这显然是ONTERMINATE的BUG。
DELPHI中类似的BUG太多了。
 
首先感谢大家的热心帮助和积极讨论!
* FreeOnTerminte为TRUE,虽然可自动清除线程对象,却不能将线程对象指针
置成 nil。这样会给编程带来很多麻烦,你无法知道该对象是否已释放。
* 关于buffer的释放问题,线程对象中的buffer并非动态创建的,不存在释放
不释放。
* to 温柔一刀:
关于Delphi Buglist 中termiante的的安全性,能否讲详细些。看看原代码
似乎没什么问题。
 
感谢“温柔一刀”的提示!
我找到了buglist,确实是书上有错,Ontermiante 事件中释放线程对象并不安全!
感谢各位的参与!多指教!
 

Similar threads

后退
顶部