【问题标题】:Multiple Thread Delphi Stop多线程 Delphi 停止
【发布时间】:2015-05-24 18:04:37
【问题描述】:

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

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;

【问题讨论】:

  • 很难理解您所描述的问题,尤其是因为我们看不到任何代码。你能提供一个样本来证明你的问题吗?另一方面,根据您的解释,听起来您需要一个线程池,但在不知道上下文的情况下不能太确定。
  • 请阅读您自己的问题并问问自己,您是否以允许人们回答的方式解释了您的问题。
  • 请显示一些实际代码。听起来您的框架/线程试图访问在创建新框架/线程时被锁定并在释放时解锁的东西,从而阻止访问早期的框架/线程实例。如果没有看到你真正在做什么,很难确定。
  • 这里有很多错误。泄漏线程。从主线程调用 Execute。同步非终止函数。您需要重新开始,并确保您有更好的理解。我很难明白为什么你需要一个线程。在您有更好的理解之前,您需要避免超出您当前专业知识的线程。
  • 说真的,tpTimeCritical 优先级?这意味着你对自己在做什么一无所知。这几乎没有任何借口。您也不能在线程过程中调用 ProcessMessages(尽管它现在在主线程中执行 - 它不应该在那里)。

标签: multithreading delphi


【解决方案1】:

您没有正确使用TThread。您没有启动线程(因此终止时它不会自行释放),您正在直接调用Execute(),您正在Synchronizeing 整个Execute()。所以Execute()在主线程中运行,调用ProcessMessages()来允许新的按钮点击,它调用Execute()阻塞之前的Execute()直到新的Execute()退出,等等。这就是您出现所见症状的原因。

要解决此问题,您需要执行以下操作:

  • 在线程构造函数中,改为调用inherited Create(False)。这允许线程自动开始运行。否则,必须在构造函数退出后调用线程的Resume()Start()方法。

  • Click() 中删除Execute()。让正在运行的线程调用Execute()

  • Teste() 中删除ProcessMessages()。永远不需要在线程中调用ProcessMessages()(除非在主线程中运行的Synchronized 或Queued 代码内部调用它,但即便如此也应尽可能避免)。

  • 只有 Synchronize() 实际上需要在主线程中运行的小代码块 - 在辅助线程中不起作用的代码、需要访问 UI 的代码、需要访问多个线程共享的资源等。你的大部分线程代码不应该是Synchronized,这首先违背了使用线程的目的。

试试这样的:

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;

【讨论】:

  • 访问共享资源的代码通常最好用锁来保护。所以我会进一步建议限制同步的使用。我只会将它用于与 UI 线程有关联的代码。
  • TThread.Resume 已弃用。 TThread.Start 应该用于启动新创建的线程。 TThread.Resume
  • @DalijaPrasnikar:是的,但我不想假设,因为内核没有说明正在使用哪个版本的 Delphi。 Start() 适用于 D2010+。
  • 我明白你的意思,但我认为这是值得一提的回答。
猜你喜欢
  • 2010-12-16
  • 2012-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多