4

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

4

3 回答 3

17

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

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

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

听起来这篇文章可能会有所帮助

如果您单击该链接,您会看到什么:

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

作者:加里詹森

摘要:信号量用于协调多个线程和进程。本文中描述的 TFixedConnectionPool 类强调了信号量为多个线程提供了对共享资源的同时访问。

于 2009-07-29T21:46:32.747 回答
2

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

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 内容。

希望有帮助。施普林格骑士

于 2013-12-18T20:57:03.207 回答