多线程Delphi停止

时间:2015-05-24 18:04:38

标签: multithreading delphi

我有一个框架,在它里面我有一个线程,这个前面的创建和在运行时,每次点击给它按钮它创建一个新的框架,并可能在表单中无数。问题是......我创建第一个,线程在我创建第二个时开始正常,第一个线程开始,第二个开始,如果我再次单击,第一个和第二个静止,第三个开始,如果我关闭第三,第二回工作,因为这发生了? 谢谢

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;

1 个答案:

答案 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;
相关问题