我有一个框架,在它里面我有一个线程,这个前面的创建和在运行时,每次点击给它按钮它创建一个新的框架,并可能在表单中无数。问题是......我创建第一个,线程在我创建第二个时开始正常,第一个线程开始,第二个开始,如果我再次单击,第一个和第二个静止,第三个开始,如果我关闭第三,第二回工作,因为这发生了? 谢谢
constructor TMy_Thread.Create(fraConnect : TfraConnect);
begin
inherited Create(True);
Priority := tpTimeCritical;
FreeOnTerminate := true;
fraConnectT := fraConnect;
end;
procedure TMy_Thread.Execute;
begin
Synchronize(Teste);
end;
procedure TMy_Thread.TEste;
var
iSize : Int64;
iCnt : Integer;
Msg : TMsg ;
begin
inherited;
with fraConnectT do begin
While not Terminated do begin
Log(fraConnectT.Name,'');
Application.ProcessMessages;
end;
end;
end;
////////////////
procedure TfraConnect.Click(Sender: TObject);
var
Sc : TMy_Thread;
begin
Sc := TMy_Thread.Create(Self);
try
iTela := 0;
Sc.Execute;
finally
Sc.Terminate;
end;
end;
答案 0 :(得分:6)
您没有正确使用TThread
。你没有启动线程(所以当它终止时它不会自由释放),你直接调用Execute()
,你Synchronize
整个Execute()
。因此Execute()
在主线程中运行,调用ProcessMessages()
以允许新的按钮点击,这会调用Execute()
阻止之前的Execute()
,直到新的Execute()
退出,等等。这就是为什么你会遇到你所看到的症状。
要解决此问题,您需要执行以下操作:
在线程构造函数中,请调用inherited Create(False)
。这允许线程自动开始运行。否则,您必须在构造函数退出后调用线程的Resume()
或Start()
方法。
从Execute()
移除Click()
。让正在运行的线程调用Execute()
。
从ProcessMessages()
移除Teste()
。永远不需要在线程中调用ProcessMessages()
(除非在主线程中运行的Synchronize
d或Queue
d代码内部调用,但即使这样也应该避免如果可能的话。
只有Synchronize()
实际需要在主线程中运行的小代码块 - 在辅助线程中无效的代码,需要访问UI的代码,需要访问由多个线程共享的资源的代码等。大部分线程代码不应该是Synchronize
d,这首先会破坏使用线程的目的。
尝试更像这样的事情:
type
fraConnect = class;
TMy_Thread = class(TThread)
private
fraConnectT : TfraConnect;
procedure DoLog;
protected
procedure Execute; override;
public
constructor Create(fraConnect : TfraConnect);
property Terminated;
end;
...
constructor TMy_Thread.Create(fraConnect : TfraConnect);
begin
inherited Create(True);
Priority := tpTimeCritical;
FreeOnTerminate := true;
fraConnectT := fraConnect;
end;
procedure TMy_Thread.Execute;
begin
with fraConnectT do begin
While not Terminated do begin
// assuming Log() is not thread-safe...
Synchronize(DoLog);
Sleep(100);
end;
end;
end;
procedure TMy_Thread.DoLog;
begin
Log(fraConnectT.Name,'');
end;
type
TMy_Thread = class;
TfraConnect = class(TFrame)
Start: TButton;
Stop: TButton;
StartClick(Sender: TObject);
StopClick(Sender: TObject);
private
Sc: TMy_Thread;
procedure ThreadTerminated(Sender: TObject);
end;
...
procedure TfraConnect.StartClick(Sender: TObject);
begin
if (not Assigned(Sc)) or Sc.Terminated then
begin
Sc := TMy_Thread.Create(Self);
Sc.OnTerminate := ThreadTerminated;
Sc.Resume; // or Sc.Start;
end;
end;
procedure TfraConnect.StopClick(Sender: TObject);
begin
if Assigned(Sc) then
Sc.Terminate;
end;
procedure TfraConnect.ThreadTerminated(Sender: TObject);
begin
if Sc = Sender then
Sc := nil;
end;