【问题标题】:AcceptSocket does not respect a Thread.Abort request [duplicate]AcceptSocket 不尊重 Thread.Abort 请求 [重复]
【发布时间】:2011-04-25 12:21:38
【问题描述】:

我的理解是 Thread.Abort 应该在阻塞的线程上引发 ThreadAbortException,但是在处理 TcpListener.AcceptSocket 时似乎并非如此。这是该问题的最基本说明:

class Program
{
    static void Main(string[] args)
    {
        Thread thread = new Thread(Listen);
        thread.Start();
        Thread.Sleep(1000); // give it a second to get going
        Console.WriteLine("Aborting listener thread");
        thread.Abort();
        thread.Join();
        Console.WriteLine("Listener thread finished press <enter> to end app.");
        Console.ReadLine();
    }
    static void Listen()
    {
        try
        {
            Console.WriteLine("Starting to listen");
            TcpListener listener = new TcpListener(IPAddress.Any, 4070);
            listener.Start();
            Socket socket = listener.AcceptSocket();
            Console.WriteLine("Connected!");
            return;
        }
        catch (ThreadAbortException exception)
        {
            Console.WriteLine("Abort requested");
        }
    }
}

thread.Abort() 调用应该停止AcceptSocket 并执行ThreadAbortException 处理程序。但是这不会发生。

将我的 AcceptSocket 的 Listen 包装器换成 ListenAsync,它调用 BeginAcceptSocket

static void ListenAsync()
    {
        try
        {
            ManualResetEvent clientConnected = new ManualResetEvent(false);

            Console.WriteLine("Starting to listen");
            TcpListener listener = new TcpListener(IPAddress.Any, 4070);
            listener.Start();
            clientConnected.Reset();
            var iasyncResult = listener.BeginAcceptSocket((ar) =>
            {
                Socket socket = listener.EndAcceptSocket(ar);
                Console.WriteLine("Connected!");
                clientConnected.Set();
            }, null);
            clientConnected.WaitOne();

            return;
        }
        catch (ThreadAbortException exception)
        {
            Console.WriteLine("Abort requested");
        }
    }

在这种情况下,它“似乎”可以正常工作。线程执行 WaitOne 时捕获 ThreadAbortException。然而,通过调用 BeginAcceptSocket 创建的线程仍在运行并且能够接受套接字(我通过使用 Telnet 打开该端口来验证这一点)

最后,我添加了 Listener.Stop 作为 TheadAbortException 处理程序的一部分,并在 EndAcceptSocket 调用周围进行了尝试捕获(因为套接字由 Stop 处理)

这真的是启动和停止侦听套接字连接过程的最佳方法吗?

【问题讨论】:

  • 当你杀死线程时,clientConnected 事件会发生什么?你为什么不处理物品?一旦被接受,你会如何处理套接字?
  • 使用Thread.Abort 几乎总是一种肮脏的黑客行为,应该避免。让你的线程优雅地终止......不要从它们下面拉地毯。

标签: c# multithreading sockets


【解决方案1】:

Thread.Abort 不中止正在侦听套接字的线程的原因是因为该线程在listen() 内核调用内部(道德等价物)被阻塞。 ThreadAbortException 只能在 CLR 实际执行时由 CLR 引发,并且在调用 listen 期间,线程实际上卡在非托管系统调用中。一旦对listen 的调用返回并且在CLR 内恢复执行,就可以继续线程中止。

我赞同不要使用Thread.Abort() 的建议。如果您决定走那条路,您可以使用类似于第二个示例中的技术。但是,当您想关闭线程侦听器时,最好使用不同的方法并简单地调用Listener.Stop()

【讨论】:

  • 我不确定 Thead.Abort() 有什么问题,但我很乐意听取建议并将调查其他选项。
  • @Ralph:从广泛的角度来看,Thread.Abort 存在问题,因为:a)(如您在此处看到的),它给人一种错误的看法,即目标线程将立即(甚至很快) 被中止,但是 CLR 受非托管代码的支配,并且 b) 它具有破坏性,并且不知道线程在中止时将处于什么状态。强烈建议您改为使用某种取消/中止标志,并尽可能使用带有超时的阻塞方法。这样您就可以检查您的取消标志,并在当时进行任何适当的清理(如果有的话)。
猜你喜欢
  • 1970-01-01
  • 2011-03-09
  • 1970-01-01
  • 1970-01-01
  • 2011-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-15
相关资源
最近更新 更多