2015-05-24 99 views
0

我有一个框,里面我有一个线程,创建在运行时这方面的和,每一次点击,让该按钮,它会创建一个新的框架,并可以在表单中有无数。问题是......我创建第一个,当我创建第二个,第一个线程到第二个时,线程开始正常,如果再次单击,第一个和第二个静止,第三个开始,如果我关闭第三个,第二个回到工作,因为这发生? 多线程德尔福停止

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

请阅读你自己的问题,并问问你自己是否以一种可以让人回答的方式解释你的问题。 –

+0

请显示一些实际的代码。这听起来像你的框架/线程试图访问一些在创建新的框架/线程时被锁定的东西,并在释放时解锁,从而阻止访问早期的框架/线程实例。很难说没有看到你真的在做什么。 –

回答

6

您没有使用正确TThread谢谢你。你是不是启动线程(因此终止时不会释放自己),你在呼唤Execute()直接,你是Synchronize荷兰国际集团的Execute()整个身体。所以Execute()运行在主线程,调用ProcessMessages()允许一个新的按钮点击,它调用Execute()阻塞以前Execute(),直到新的Execute()退出,等等。这就是为什么你正在经历你所看到的症状。

要解决这个问题,你需要做到以下几点:

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

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

  • Teste()删除ProcessMessages()。从未有一个需要调用ProcessMessages()在一个线程(除非它被调用Synchronize d或在主线程中运行Queue d码之内,但即使如此,它应该尽量避免)。

  • 只有Synchronize()小代码块,实际上需要在主线程中运行 - 这需要访问多个共享资源的代码,不辅助线程工作,需要访问的用户界面代码,代码线程等。大部分线程代码不应该是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; 
+1

访问共享资源的代码通常受锁的最佳保护。所以我会进一步建议限制Synchronize的使用。我只会将它用于对UI线程有亲和力的代码。 –

+2

'TThread.Resume'已弃用。 'TThread.Start'应该用于启动新创建的线程。 [TThread.Resume](http://docwiki.embarcadero.com/Libraries/XE8/en/System.Classes.TThread.Resume) –

+0

@DalijaPrasnikar:是的,但我不想推定,考虑到Kernel没有说哪个Delphi的版本正在被使用。 '开始()'用于D2010 +。 –