为啥 Thread.Abort 仅在 isBackground 属性设置为 true 时才有效?

Posted

技术标签:

【中文标题】为啥 Thread.Abort 仅在 isBackground 属性设置为 true 时才有效?【英文标题】:Why Thread.Abort only works if is isBackground property set to true?为什么 Thread.Abort 仅在 isBackground 属性设置为 true 时才有效? 【发布时间】:2014-05-10 20:26:06 【问题描述】:

我正在开发一个微型 UDP 控制台来发送一些数据来测试一些 GPRS 设备,所以我修改了我在 CodeProject 中找到的一个示例,它使用一个线程;但是当我想退出应用程序时遇到问题,即使我做了类似的事情,tread 也拒绝停止

If UdpOpen Then
   ThreadReceive.Abort()
   Me.Dispose()
   UdpOpen = False
End If

它停在第一行代码

Private Sub UdpReceive()
    Dim receiveBytes As [Byte]() = receivingUdpClient.Receive(RemoteIpEndPoint) '<--Halt here
    IpRemote(RemoteIpEndPoint.Address.ToString)
    Dim BitDet As BitArray
    BitDet = New BitArray(receiveBytes)
    Dim strReturnData As String = System.Text.Encoding.ASCII.GetString(receiveBytes)
    If UdpOpen Then
        StartUdpReceiveThread(CInt(RemotePortLbl.Text))
    End If

    PrintLog(strReturnData)
End Sub

所以我做了一些研究,通常在这个网页中找到了解决方案 Stop a thread that prevents program to close?

而且,正如第一条评论所说,我将 isBackground 属性设为 True 并且它可以工作,现在的问题是为什么?

是否有人更深入地了解它的工作原理?

【问题讨论】:

【参考方案1】:

.NET 内置了对异步接收 UDP 的支持。看到这个:

UdpClient.BeginReceive

所以在这种情况下你不需要使用线程。

【讨论】:

感谢您的回答,我目前正在使用线程,所以我想我现在要保持这种方式,但这是另一种有趣的方式。感谢分享。【参考方案2】:

只有当 CLR 知道这样做是安全的时,线程才可中止。当线程深埋在操作系统调用中时,情况就不会如此。这从根本上说是不安全的,因为 CLR 无法知道线程是否获得了任何需要再次释放的内部操作系统锁。

通过将 IsBackground 属性设置为 true,您可以告诉 CLR 可以中止线程,但将其留给操作系统进行清理-up 任何需要发布的东西。任何被占用的锁都不会再导致任何问题,因为任何可能死锁的代码都无法再运行。操作系统负责释放套接字使用的操作系统资源。就像您的程序因任何其他原因中止(例如您使用任务管理器终止它)一样。

正确的方法是调用套接字的 Dispose() 方法。这会在操作系统调用时拉下地板垫,它将停止等待接收任何内容,因为套接字是一只死鹦鹉。 Receive() 调用将完成一个 ObjectDisposedException,准备好捕获它。

另一个非常常见的场景是根本不使用线程,而是使用 BeginReceive()。清理的工作方式大致相同,当您调用 Dispose() 时,回调将运行。当您调用 EndReceive() 时,您会得到 ObjectDisposedException。同样,准备好抓住它并迅速离开,而不用对套接字做任何其他事情。

使用 Thread.IsBackground 是处理关机的一种非常合理的方式,假设您不必做任何复杂的事情来告诉线路另一端的程序您停止侦听消息。

【讨论】:

感谢您的回答,我的 UDP 控制台为收到的每个数据包发送一个 ACK​​ 数据包到远程设备,所以如果远程设备没有收到 ACK,他就知道数据包没有到达我的控制台或者控制台没有运行,所以我不需要向远程设备发送任何东西来警告它。我目前管理线程的方式,没有任何机会让一个孤独的线程在操作系统中走动,对吧? 太模糊了,我不知道“行走”线程是什么样的。或者 ACK 的意思是“我收到了”还是“我处理了”。实现自己的 TCP 版本通常是一个错误。可靠的UDP之前已经做过很多次了。 “行走线程”是指即使我关闭应用程序仍会运行的线程。是的,Ack 代表 ACKnowledge。我没有创建自己的 TCP 堆栈,我有一个要模拟的协议,因为它已经在我工作的服务器中实现了。 问和回答。与了解该协议的人交谈,您不太可能在该服务器不知道的情况下终止您的程序。 控制台没有连接到服务器,它模拟它是为了测试通常连接到主服务器的远程设备。我的 UDP 控制台仅供技术人员的笔记本电脑测试远程设备,不在任何服务器上运行。

以上是关于为啥 Thread.Abort 仅在 isBackground 属性设置为 true 时才有效?的主要内容,如果未能解决你的问题,请参考以下文章

Thread.Abort() 并在 finally 之后延迟

Thread.Abort 的安全异常

可以像中止一个Thread(Thread.Abort方法)一样中止一个Task吗?

.NET Thread.Abort 再次

在没有“Thread.Abort()”的情况下立即停止 C# 线程

如何抑制 thread.abort() 错误 C#?