【问题标题】:Thread.Start is not returning in some sparse cases in my c# applicationThread.Start 在我的 c# 应用程序中的某些稀疏情况下没有返回
【发布时间】:2012-04-12 20:06:37
【问题描述】:

我用 C# 编写了一个 TCP 服务器应用程序。应用程序监听入站连接

在主监听线程中使用 TcpListener.AcceptTcpClient() 方法。

当接收到连接时,TcpListener.AcceptTcpClient() 解除阻塞并返回 TCPClient 对象。

收到连接后,会创建一个新线程并开始将数据读写到新连接。

新线程由以下代码启动。

while(true)
{
  TcpClient client = serverListener.AcceptTcpClient();


  if (client.Connected)
  {
    Thread t = new Thread(delegate() { readWriteData(client); });
    t.IsBackground = true;
    t.Start(); /// Problem happens here. The thread gets stuck here and doesn't move   further
  }
 }

应用程序运行良好,但有时在 Windows 7 机器上,应用程序突然停止侦听 tcp 连接。

分析此状态下应用程序的线程堆栈,(使用Microsoft stack explorer查看应用程序所有线程的堆栈)发现主监听线程卡在上面代码部分的以下行

 t.Start(); /// Problem happens here. The thread gets stuck here and doesn't move   further

我进行了大量研究,但找不到发生这种情况的原因。此行为仅在 Windows 7 系统中观察到。

谁能帮我解决这个问题。

按照 Rob 的建议,

我在这里发布由 windbg (sos) 显示的堆栈跟踪

0547eae0 7282e006 mscorwks!Thread::StartThread+0xc3, calling mscorwks!_EH_epilog3
0547eb00 727ac825 mscorwks!__SwitchToThread+0xd, calling mscorwks!__DangerousSwitchToThread
0547eb10 728b9c6f mscorwks!ThreadNative::StartInner+0x1ba, calling mscorwks!__SwitchToThread
0547eb58 727e4b04 mscorwks!SafeHandle::DisposeNative+0x3a, calling mscorwks!LazyMachStateCaptureState
0547ebc8 728b9d80 mscorwks!ThreadNative::Start+0xa6, calling mscorwks!ThreadNative::StartInner
0547ec18 728b9d01 mscorwks!ThreadNative::Start+0x1f, calling mscorwks!LazyMachStateCaptureState
0547ec74 71de6afc (MethodDesc 0x71c13048 +0x8c System.Threading.Thread.Start()), calling mscorwks!ThreadNative::Start
0547ec8c 030e2a46 (MethodDesc 0x30da408 +0x25e WindowsService.Server.startListener()), calling (MethodDesc 0x71c13048 +0 System.Threading.Thread.Start())

【问题讨论】:

  • Thread.Start 不太可能没有返回。更有可能是您检查或确定错误的方法。是什么让您认为 Thread.Start 没有返回?
  • 通常不建议每个连接都有一个线程;它不会缩放。您有多少传入连接?
  • 挂起时您有多少活跃客户? - 每个客户端的线程并不总是很好地扩展。
  • 你能直接确认这个行为吗(没有附加调试器,或者通过查看转储)?尝试在t.Start() 前后使用日志语句或Console.WriteLine,写出线程管理的ID 或类似的东西,然后确认您确实遇到了“之前”消息而没有相应的“之后”消息。
  • @KierenJohnstone 如帖子中所述,我使用 microsoft stack explorer 查看卡住线程的堆栈。每次出现这个问题,就说明主监听线程的状态是running,线程卡在Thread.start上

标签: c# multithreading windows-7 tcp


【解决方案1】:

我仍然没有找到上述问题发生的根本原因。但是,为了防止我的应用程序因为这种情况而失败,我实施了以下解决方法。

修改后的代码如下。

count = 0;

while(true)
{
  TcpClient client = serverListener.AcceptTcpClient();


  if (client.Connected)
  {
    Thread t = new Thread(delegate() { readWriteData(client); });
    t.IsBackground = true;

    ++count;
    t.Start(); /// Problem happens here. The thread gets stuck here and doesn't move   further
    ++count;
  }

}

我在另一个线程中检查,如果 count 的值在 5 秒内没有改变并且 count 的值是奇数,这意味着侦听器线程卡在 t.start() 上。在这种情况下,我会终止当前的侦听器线程并启动新的。

【讨论】:

    【解决方案2】:

    我想我已经解决了这个问题。

    我确实错误地关闭了另一个线程中的打开句柄。我通过 pinvoke 使用本机关闭方法在一个线程中关闭了两次相同的句柄。可能会发生在第一次关闭句柄后,相同的句柄被分配到进程内部的某个位置。在执行了第二次关闭之后,但它实际上关闭了打开的句柄,因此导致过程中出现无法解释的不适用性。

    删除第二次关闭后,问题不再出现。

    【讨论】:

      【解决方案3】:

      不确定这是否能解决您的问题:

          // Start ThreadProc.  Note that on a uniprocessor, the new 
          // thread does not get any processor time until the main thread 
          // is preempted or yields.  Uncomment the Thread.Sleep that 
          // follows t.Start() to see the difference.
          t.Start();
          //Thread.Sleep(0);
      
          for (int i = 0; i < 4; i++) {
              Console.WriteLine("Main thread: Do some work.");
              Thread.Sleep(0);
          }
      

      来源:http://msdn.microsoft.com/en-us/library/system.threading.thread.aspx

      解决您的问题的另一种方法可能是使用 TCPListener 异步:
      http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.beginaccepttcpclient.aspx

      【讨论】:

      • 它仍然可以被抢占,所以这不会改变它 working - 它只会改变 promptly 其他线程显示的方式
      • 我的问题是我的主线程永久卡在 Thread.start 上。我认为这不能通过强制抢占任何线程来解决。
      • 这只是额外的延迟。侦听器线程在循环返回时很快会阻塞 accept() 调用 - 不需要任何 sleep() 东西。
      • 在我的代码某处 CloseHandle(IntPtr hObject);像这样 CloseHandle(handle); 连续调用了两次;关闭句柄(句柄);它创建了赛车代码,第二次关闭是关闭分配给某些内部进程功能的句柄
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-05
      • 2015-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-04
      • 2016-09-08
      相关资源
      最近更新 更多