【问题标题】:how to close a thread containing a blocking method in C#如何在 C# 中关闭包含阻塞方法的线程
【发布时间】:2013-02-09 06:59:15
【问题描述】:

我创建了一个线程来处理我的代码中的阻塞方法。这样,我的代码除了运行该阻塞方法之外还可以做其他事情。

问题:如何正确终止线程?我是否必须解除阻塞方法,然后终止线程。还是我可以直接终止线程而不用担心任何丑陋的崩溃?

【问题讨论】:

  • 如果您不希望线程永远阻塞,请不要将其编码为。真的就是这么简单。任何时候你觉得你需要从外部进入并强制线程做某事,这只是证明你没有编写线程来做你真正想做的事情。

标签: c# multithreading methods blocking terminate


【解决方案1】:

致电yourthread.Abort()。不像过去那样,当资源和锁没有被释放时,这会导致你破坏一切,现在这会引发一个非常好的异常,可以用正常的方式处理......

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

当我说“正常方式”时,似乎线程中止异常自动重新引发(相当不错的技巧)

http://msdn.microsoft.com/en-us/library/system.threading.threadabortexception.aspx

但这并不能阻止你成为一个混蛋并在 catch 块中开始另一件大事......

【讨论】:

  • MSDN 说 Abort() '通常会终止线程'。有保证关闭它的方法吗? =/
  • 实际上,进行了一些试验,这并不是那么简单——即使处理后异常似乎也会传播......(参见msdn.microsoft.com/en-us/library/…
  • 啊,好老 Thread.Abort...烧掉你的房子来杀死你看到的那只蜘蛛...
  • 其实并不能保证。线程可能根本看不到异常。文档的备注部分有一长串例外情况。
【解决方案2】:

你有一些选择。如果您不关心在应用程序关闭时操作是否完成,您最好通过QueueUserWorkItem 使用 ThreadPool 线程,或者(如 Servy 在 cmets 中建议的那样)将线程的 IsBackground 属性设置为 true,这将允许进程在线程不退出的情况下退出。

如果您确实关心操作的完成和/或需要在关机时运行的清理逻辑,那么您可能并不想使用 Thread.Abort,至少不是您的 goto 策略。我使用的是类似这样的:

public abstract class DisposableThread : IDisposable
{
    private ManualResetEvent exiting = new ManualResetEvent(false);
    private Thread theThread;
    private  TimeSpan abortTimeout;

    public DisposableThread():
        this(TimeSpan.FromMilliseconds(100))
    {
    }

    public DisposableThread(TimeSpan abortTimeout)
    {
        this.abortTimeout = abortTimeout;
        theThread = new Thread((_) => ThreadProc());
    }

    protected virtual void ThreadProc()
    {
        while(!exiting.WaitOne(0))
        {
            WorkUnit(exiting);
        }
        ThreadCleanup();
    }

    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        exiting.Set();
        if (!theThread.Join(abortTimeout))
        {
            // logme -- the thread didn't shutdown gracefully
            theThread.Abort();
            while (!theThread.Join(1000))
            {
                // logme -- the thread is doing something dumb in an exception handler
            }
        }
        exiting.Dispose();
    }

    // WorkUnit should return as quickly as safe if the exiting handle is set
    // If it doesn't the thread will be aborted if it takes longer than abortTimeout
    protected abstract void WorkUnit(WaitHandle exiting);

    // override if you need to cleanup on exit
    protected virtual void ThreadCleanup() { }
}

这让您的线程有机会优雅地退出,并且只有在优雅退出失败时才会中止。

【讨论】:

  • 您不想将运行时间很长的操作放入线程池线程中。您应该只通过IsBackground = true 将您创建的线程标记为后台线程。
  • 那么对于我提到的网站中的示例,如何正确关闭2个线程? =/
【解决方案3】:

好的, 找到了我的答案。我必须声明线程,以便可以对它们进行引用。然后,我首先结束嵌套线程(它具有 HandleClientComm()),然后关闭 TCP_Client(如果不为空)和 TCP_Listener。然后我结束 ListenThread()。还有,这里Proper way to stop TcpListener提到的TCP_Listener.Pending()方法必须实现。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-02
    • 2013-02-27
    • 1970-01-01
    • 1970-01-01
    • 2010-10-11
    • 1970-01-01
    • 2018-02-16
    相关资源
    最近更新 更多