Thread能否重用?(50分)

  • 主题发起人 主题发起人 maorui
  • 开始时间 开始时间
M

maorui

Unregistered / Unconfirmed
GUEST, unregistred user!
一个Thread.Resume之后,再次执行好象只能用Thread.Execute。
但是Execute结束之后,主线程才能继续。这里需要怎样处理才能让主线程也同时运行下去?
 
给你一个例子
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TMyThread = class(TThread)
public
procedure Execute;
override;
end;

TForm1 = class(TForm)
Edit1: TEdit;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
Stoped: Boolean;
CurPos: Integer;
implementation
{$R *.dfm}
{$R WindowsXP.res}
procedure TForm1.Button1Click(Sender: TObject);
var
MyThread: TMyThread;
begin
MyThread := TMyThread.Create(False);
MyThread.FreeOnTerminate := True;
end;

{ TMyThread }
procedure TMyThread.Execute;
var
I: Integer;
begin
inherited;
Stoped := False;
for I := CurPos to 1000000do
begin
if Stoped then
begin
CurPos := I;
Exit;
end;
Form1.Edit1.Text := IntToStr(I);
end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
Stoped := True;
end;

end.
 
楼上理会错了。
我是说同一个Thread对象,已经用resume执行过,但还没有Destroy。想直接再次执行这些Thread。
 
不会吧
派生线程和主线程应该是同步运行的,主线程不等它
除非你需要可以用线程同步
 
现在就是不行啊。
thread.freeonterminate := false;
有两个for循环
第一个for里面使用resume,可以保证所有thread同时运行。
第二个for循环必须使用execute了,因为resume会不执行而马上退出。结果thread是一个一个execute的。可以根据thread里面记录的时间看出来。
 
to maorui 把你的thread.execute贴出来
execute中你没有使用 while not terminateddo
?
 
代码太长了,大致上是这样的:
主Thread里面
threads.create(True);
threads.resume;
//其他处理
threads.execute;
//这里出现问题,thread逐个运行了。
threads.free;
工作Thread的execute没什么特殊代码,进行处理后正常返回。
工作循环里面有if Terminated then
break;
工作Thread只重载了create和destory。
resume运行是正常的,只有后来的execute出问题。
 
首先解释一下,
线程对象在创建后,若未挂起或挂起后,被其他线程Resume,则自动执行线程的Excute方法;Excute执行完毕,线程结束运行,就等你释放了。Excute一般不要显示调用。
你的程序有明显问题:
估计这样:你在A线程(通常VCL线程)创建你所说的主线程,在执行到
threads.Resume后,你的主线程实际已经进入excute的处理;你又调用了Excute,实际在A线程里又执行了一遍threads的Excute方法,反正是给你搞乱了。
估计你的工作线程也是 创建+Resume+Execute了(这样肯定要逐个运行的,实际是每个Excute都来了两遍,估计你的结果也是乱的)
这样做:
Threads.Create(true);
Threads.FreeOnTerminate:=true;//线程运行结束,自动释放
Threads.Resume;//别再出现 threads.Excute了
估计工作线程也这问题
如果你想重复执行某线程,则要么每次创建一个,要么在Excute里处理
在Excute里处理,可以这样写:
begin
FreeOnTerminate:=false;
repeat
if not Terminated then

begin
//处理
end;
if not Terminated then
Suspend;
//挂起,再想执行时,通过别的线程(如VCL线程)执行Resume
until terminated;
end;

由于线程执行中被挂起,释放线程(如程序退出时),需要执行:
Threads.Terminate;
Threads.Resume;
Threads.WaitFor;
Threads.Free;
 
线程没有结束要再使用,就得再创建一个。
 
to maorui Avenir说得很对,你在thread.excute中要使用循环,不然即使你的FreeOnTerminate:=false;该线程也结束了,当然下次resume就不起作用了。
 
Avenir的意思是说,Execute被设计成protected可视性,是专门留给线程函数调用的,如果你执行Execute方法,结果便是在主线程中运行你本该在线程中运行的代码。如果在线程中有等待函数被将线程阻塞,当然得等它运行完了主线程才熊继续。
所以你如果想让线程能够重用,千万别让Execute结束了。如果结束了而你用FreeOnTerminate=Fasle那就惨了,闹不好内存泄漏。俺一直弄不懂Delphi为什么设计FreeOnTerminate这个属性,并且缺省值为False,觉得非常多余。俺至今没发现什么地方用过它。
线程对象重用其实非常简单。你看看ScktComp.pas单元中TServerClientThread就设计成可重用的。不过,用户重载的可不是Execute方法而是ClientExecute方法,然后Execute方法不断地调用ClientExecute方法。每次运行快玩完的时候用一个事件等待函数对象阻塞住,如果这时候Terminated为False,线程又复活了。
 
谢谢大家,我明白问题所在了。
本来我是想节省Thread.Create和Destroy的时间,因为这两个过程比较长。现在看来最好是重新创建了。
信号阻塞的方法也不错,但对于我的程序修改量比较大了,以后我再试着修改。
 
后退
顶部