【问题标题】:delphi - terminate all the threads (TThread) on closing applicationdelphi - 在关闭应用程序时终止所有线程(TThread)
【发布时间】:2010-11-15 05:57:31
【问题描述】:

我的应用程序是一个 tcp/ip 服务器,主线程只创建一次并一直在监听。当新客户端连接时,主线程创建TClientThread 类型的新线程。但是没有正在运行的客户端线程列表,因为这会使我的应用程序有点复杂......有没有办法在所有线程上执行“终止”方法,即使线程很忙(在我的情况下是“忙”意味着它正在等待数据,其中超时设置约为 30 秒......所以无论如何我都必须杀死它,而无需等待。)? 简单的关闭应用程序似乎没有在线程上运行“终止”方法,最终导致 FastMM 报告内存泄漏......

【问题讨论】:

    标签: delphi terminate fastmm tthread


    【解决方案1】:

    关机时的内存泄漏无需担心 - 在将控制权返回给操作系统之前释放内存的麻烦是浪费时间并且不必要地减慢应用程序的退出速度。您真正需要做的就是确保所有数据都已保存,并且所有进程间句柄(例如信号量和互斥量)都正确释放,然后退出。

    为了通知客户,你能做的最好的策略是这样的:

    • 将所有客户端处理线程添加到某个列表中(对创建、销毁和迭代进行适当锁定)
    • 让客户端线程在终止时将自己从列表中删除,如果服务器正在关闭,则从列表中删除的最后一项设置一个事件(手动重置事件,例如 SyncObjs 中的TEvent
    • 在原本会长时间运行的阻塞例程中引入轮询(例如 select 或具有超时的等效项)或其他类型的中断(例如 SO_RCVTIMEO / SO_SNDTIMEO),监控 Terminated 属性
    • 关闭时,锁定列表并遍历它,调用Terminate,然后等待事件发出信号;当然,将项目添加到列表中的侦听套接字应该在遍历列表之前关闭并且已知已关闭

    【讨论】:

    • 事实上,线程需要正确终止才能让应用知道将其客户端状态保存为断开连接...所以无论如何我都需要知道该怎么做!
    • 关机时的内存泄漏没什么好担心的:也许这就是我几乎每次关闭 Delphi IDE 时都会遇到灾难性故障的原因。
    • Tihauan - 卸载包是另一回事,例如,包可能会重复加载和卸载。至于为什么 IDE 在关闭时为您崩溃,如果没有更多数据,我无法推测。
    • 关机时的内存泄漏值得担心。它们是一种信号,表明您的代码中可能存在一些问题。您不能忽略它们,但是一旦您知道这些泄漏发生的原因和时间并且它们并不危险,您就可以接受它们。
    【解决方案2】:

    Sounds like this article may help

    点击该链接会看到什么:

    在 Delphi 中使用信号量,第 2 部分: 连接池

    作者:加里·詹森

    摘要:信号量用于 协调多个线程和 过程。信号量提供 多个线程同时 访问共享资源是 突出显示 TFixedConnectionPool 类描述 在这篇文章中。

    【讨论】:

    • 信号量是一种同步结构,与 OP 的问题无关(在关闭时终止线程)
    【解决方案3】:

    我使用 KillThreadList: TList 全局。 我在我的线程中监控它:

    while (Not Terminated) do
    begin
      inc(Inker);
      if (WaitForSingleObject(FTick, finterval) = WAIT_TIMEOUT) then
      Begin
        if Inker >= 10 then
        Begin
          ProcessTables;
          Inker := 0;
          sleep(1000);
        End;
        if KillThreadList.Contains(ThreadID) = True then Terminate;
      End;
    end;
    

    我还在我的进程中测试了 KillThreadList,让我在完成之前选择退出它们,这样做是安全的。

    我将 OnTerminate 事件传递给主线程并从那里的 KillList 中删除 ThreadID。我广泛使用这个模型,它还没有让我失望。

    procedure TfrmProcessQualcommLocations.OnTerminateThread;
    var
      ThreadID : Cardinal;
      i : integer;
      aStatusBar :TStatFrame;
    begin
      ThreadID := (Sender as Tthread).ThreadID;
      for i := 0 to StatusBarList.Count -1  do
      Begin
        if StatusBarList.Items[i].ThreadID = ThreadID then
        Begin
          aStatusBar := StatusBarList.Items[i];
          KillThreadList.Extract(ThreadID);
          StatusBarList.Extract(aStatusBar);
          aStatusBar.Free;
          break;
        End;
      End;
    
      self.Refresh;
    end;
    

    在上述情况下,我还删除了一些 GUI 内容。

    希望对您有所帮助。 斯普林格骑士

    【讨论】:

    • " = True" 太棒了!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多