【问题标题】:Thread.Abort() stucks at NetworkStream.Read?Thread.Abort() 卡在 NetworkStream.Read 上?
【发布时间】:2012-03-27 12:36:47
【问题描述】:

我有一个文件传输应用程序(服务器-客户端)...在发送文件时,我想启用取消。
客户端取消后台工作程序的 SendFile 方法,然后向服务器发送命令以取消其接收线程。
当服务器收到此命令时,它会调用 Stop 方法 但它停留在该行 network.Read(data, 0, data.Length);

我怎样才能中止这个线程并转到 finally 而不会卡在 network.Read(..) 中?
提前致谢。

Thread thTransferFile = null;

void Start()
{
    thTransferFile = new Thread(unused => ft.Receive(destPath, Convert.ToInt64(fileSize);
    thTransferFile.Start();
}

void Stop()
{
    thTransferFile.Abort();
}


public void Receive(string destPath, long fileSize)
    {
        using (fs = new FileStream(destPath, FileMode.Create, FileAccess.Write))
        {
            try
            {
                int count = 0;
                long sum = 0;
                data = new byte[packetSize];
                while (sum < fileSize)
                {
                    count = network.Read(data, 0, data.Length);   //thread stucks in this line when i abort it
                    fs.Write(data, 0, count);
                    sum += count;
                }
            }
            finally
            {
                network.Write(new byte[1], 0, 1); //tell client that the file transfer ends
                network.Flush();
                fs.Dispose();
                if (Thread.CurrentThread.ThreadState == ThreadState.AbortRequested)
                {
                    File.Delete(destPath);
                }
            }
      }

【问题讨论】:

  • Thread.Abort几乎总是做错事。
  • @Damien_The_Unbeliever 所以如果错了.. 正确的做法是什么?
  • 这取决于你感觉有多勇敢 - 如果你准备好跳转到 .NET 4.5,那么采用 CancellationTokenReadAsync 的重载效果最好。否则,正如@Daniel Mošmondor 所说,CloseDispose network 对象。

标签: c# cancellation thread-abort


【解决方案1】:

我找到了解决方案 当我取消从客户端发送时.. network.DataAvailable 设置为 false .. 所以我将此行添加到服务器中的接收方法中

在while循环中:

                while (sum < fileSize)
                {
                    if (network.DataAvailable)
                    {
                        count = network.Read(data, 0, data.Length);
                        fs.Write(data, 0, count);
                        sum += count;
                    }
                }

所以它永远不会卡在 network.Read 上。 它完全有效

【讨论】:

  • 检查可用数据绝对是朝着正确方向迈出的一步,但整体解决方案太让人想起自旋锁。当您的代码运行时,您的数据多久不可用?
  • @Tung 我没有在那个问题中解释我的代码,因为我想要的是中止线程的事情..但是我构建我的应用程序的方式..network.DataAvailable 总是正确的..直到取消或网络关闭..仅在这两种情况下。
【解决方案2】:

NetworkStream.Read 在接收到数据之前被阻塞。使用 NetworkStream 的 ReadTimeoutRead the community comment 设置读取操作的超时时间。此外,您可能需要重新考虑使用 Abort() 来终止您的线程。在 while 循环中添加一个布尔标志,并在调用 Stop() 时将该标志设置为 false。这个停止标志加上ReadTimeout 将确保您的程序最终退出。

如果正在调用 Abort 的线程可能会阻塞 aborted 位于代码的受保护区域中,例如 catch 块, finally 块,或受约束的执行区域。如果那个线程 调用 Abort 持有中止线程所需的锁,即死锁 可能发生。

【讨论】:

  • 我应该在 ReadTimeout 中设置多少时间 .. 你知道由于某种原因网络有时会滞后 .. 我不能太短以至于可能在没有取消命令的情况下取消接收 .. 为什么我应该停止使用 Thread.Abort .. 我认为它比每次收到数据包时检查标志更好 .. 加上我需要该线程执行“受保护区域”,例如 [finally] .. 所以 FileStream 在任何情况下都会处理(错误,取消,成功)。
  • @Mur,我同意 ReadTimeout 是次优的,因为您永远无法确定多长时间足够长,但高值总比无限长好。您是否考虑过使用 BeginRead 代替?正如其他成员所指出的,Abort() 通常是不可取的。人们永远无法确定线程在被中断时正在做什么。这是一个discussion。我也相信你的 finally 块只有在 Abort() 发生在 try 块中时才会被执行。
  • @Tung - 我希望您不要在错误的假设上构建代码:此方法将数据读入缓冲区参数并返回成功读取的字节数。如果没有数据可供读取,Read 方法返回 0。Read 操作读取可用数据,最多为 size 参数指定的字节数。如果远程主机关闭连接,并且已接收到所有可用数据,则 Read 方法立即完成并返回零字节。 (取自msdn.microsoft.com/en-us/library/…
  • 我想说的是:Read() 不会阻塞。
  • @Tung 你可能是对的.. 使用 beginRead 会有所帮助.. 但是当我使用 if(network.DataAvailable) 它完全有效.. 并且中止该线程再也不会卡住..
【解决方案3】:

Close() network 不是中止线程。它会像你期望的那样抛出异常。

杀死线程是一个很大的禁忌,因为有些资源可能未被清理...

【讨论】:

  • 我无法关闭()网络..每次我想发送文件时我都不会重新连接..它不会工作。
  • 然后,你将不得不使用异步的东西。 BeginRead() 等等。我知道这会使整个交易复杂化,但我不知道还有其他方法。
  • 谢谢丹尼尔..我已经想出了如何解决它..检查我的答案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-30
  • 2010-12-30
  • 2016-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多