gpt4 book ai didi

c# - 为什么在finally block 中休眠时线程不被中断

转载 作者:太空狗 更新时间:2023-10-29 17:43:45 25 4
gpt4 key购买 nike

我一直在MSDN上四处寻找,找不到找不到在finally块中休眠时无法中断Thread的原因。我尝试中止没有成功。

在finally块中休眠时,有什么方法可以唤醒线程?

Thread t = new Thread(ProcessSomething) {IsBackground = false};
t.Start();
Thread.Sleep(500);
t.Interrupt();
t.Join();

private static void ProcessSomething()
{
try { Console.WriteLine("processing"); }
finally
{
try
{
Thread.Sleep(Timeout.Infinite);
}
catch (ThreadInterruptedException ex)
{
Console.WriteLine(ex.Message);
}
}
}

令人惊讶的是,MSDN声称线程可以在finally块中中止: http://msdn.microsoft.com/en-us/library/aa332364(v=vs.71).aspx
“运行finally块时线程有可能中止,在这种情况下,finally块将中止。”

编辑
我发现Hans Passant的评论是最好的答案,因为这解释了为什么Thread在finally块中有时可以或不能被中断/中止。那就是进程关闭的时候。
谢谢

最佳答案

如果可能,应避免中止和中断线程,因为这会破坏正在运行的程序的状态。例如,假设您中止了一个线程,该线程持有对资源开放的锁,那么这些锁将永远不会被释放。

相反,请考虑使用信令机制,以便线程可以相互协作,从而优雅地处理阻塞和解除阻塞,例如:

    private readonly AutoResetEvent ProcessEvent = new AutoResetEvent(false);
private readonly AutoResetEvent WakeEvent = new AutoResetEvent(false);

public void Do()
{
Thread th1 = new Thread(ProcessSomething);
th1.IsBackground = false;
th1.Start();

ProcessEvent.WaitOne();

Console.WriteLine("Processing started...");

Thread th2 = new Thread(() => WakeEvent.Set());
th2.Start();

th1.Join();
Console.WriteLine("Joined");
}

private void ProcessSomething()
{
try
{
Console.WriteLine("Processing...");
ProcessEvent.Set();
}
finally
{
WakeEvent.WaitOne();
Console.WriteLine("Woken up...");
}
}

更新

非常有趣的低级问题。尽管已记录 Abort(),但 Interrupt()却少得多。

对您的问题的简短回答是“否”,您无法通过在其上调用 AbortInterrupt唤醒finally块中的线程。

不能中止或中断finally块中的线程是设计使然,只是为了使finally块有机会按您期望的那样运行。如果您可以中止线程并最终中断线程,则可能会对清理例程产生意想不到的后果,从而使应用程序处于损坏状态-不好。

线程中断的一个细微差别是,线程可能在进入finally块之前的任何时间都已针对该线程发出了中断,但是该中断并未处于 SleepWaitJoin状态(即未阻塞)。在这种情况下,如果在finally块中有一个阻塞调用,它将立即抛出一个 ThreadInterruptedException并从finally块中退出。最后,块保护可以防止这种情况。

除了对finally块进行保护外,它还扩展到try块以及CER( Constrained Execution Region),可以在用户代码中对其进行配置,以防止在执行区域之前引发一系列异常-对于必须执行代码的关键代码块非常有用完成并延迟中止。

异常(exception)情况(无双关语)称为 Rude Aborts。这些是CLR托管环境本身提出的 ThreadAbortExceptions。这些可能最终导致捕获块被退出,但CER却无法退出。例如,CLR可能会响应于判断为需要花费很长时间才能完成其工作\退出的线程来提高Rude Aborts。尝试卸载AppDomain或在SQL Server CLR中执行代码时。在您的特定示例中,当您的应用程序关闭且AppDomain卸载时,CLR会在 sleep 线程上发出粗鲁中止,因为会有AppDomain卸载超时。

在用户代码中不会发生final块中的中断和中断,但是这两种情况之间的行为略有不同。

中止

在finally块中的线程上调用 Abort时,调用线程被阻塞。这是 documented:

The thread that calls Abort might block if the thread that is being aborted is in a protected region of code, such as a catch block, finally block, or constrained execution region.



在中止情况下,如果 sleep 不是无限的:
  • 调用线程将发出Abort,但在此处阻塞,直到退出finally块为止,即,它在此处停止并且不立即进入Join语句。
  • 被调用者线程的状态设置为AbortRequested
  • 被叫者继续 sleep 。
  • 当被叫者醒来时,由于其状态为AbortRequested,它将继续执行finally块代码,然后“蒸发”,即退出。
  • 当异常终止的线程离开了finally块时:没有引发异常,在执行finally块之后没有任何代码,并且线程的状态为Aborted
  • 调用线程被解除阻塞,继续到Join语句,并在被调用线程退出时立即通过。

  • 因此,在您的示例中具有无限 sleep 的情况下,调用线程将在步骤1永远阻塞。

    打断

    在中断情况下,如果 sleep 不是无限的:

    没有很好的记录...
  • 调用线程将发出Interrupt并继续执行。
  • 调用线程将在Join语句上阻塞。
  • 被调用者线程的状态设置为在下一次阻止调用时引发异常,但至关重要的是,由于它在finally块中,所以它并未被解除阻止(即唤醒)。
  • 被叫者继续 sleep 。
  • 当被叫者醒来时,它将继续执行finally块。
  • 当被中断的线程离开finally块时,它将在其下一个阻塞调用中抛出ThreadInterruptedException(请参见下面的代码示例)。
  • 调用线程“加入”并随着被调用线程的退出而继续,但是,步骤6中未处理的ThreadInterruptedException现在使进程变平...

  • 因此,再次给您一个无限 sleep 的示例,调用线程将永远阻塞,但在步骤2中。

    概括

    因此,尽管 AbortInterrupt的行为略有不同,但它们都将导致被调用线程永远处于休眠状态,并且调用线程永远处于阻塞状态(在您的示例中)。

    只有粗鲁的中止才能迫使被阻塞的线程退出finally块,并且这些只能由CLR本身引发(您甚至不能使用反射来欺骗 ThreadAbortException.ExceptionState,因为它进行内部CLR调用以获取 AbortReason-没有机会被在那里容易邪恶...)。

    CLR防止用户代码导致为我们自己的利益而提前退出finally块-它有助于防止损坏状态。

    有关 Interrupt的行为略有不同的示例:
    internal class ThreadInterruptFinally
    {
    public static void Do()
    {
    Thread t = new Thread(ProcessSomething) { IsBackground = false };
    t.Start();
    Thread.Sleep(500);
    t.Interrupt();
    t.Join();
    }

    private static void ProcessSomething()
    {
    try
    {
    Console.WriteLine("processing");
    }
    finally
    {
    Thread.Sleep(2 * 1000);
    }

    Console.WriteLine("Exited finally...");

    Thread.Sleep(0); //<-- ThreadInterruptedException
    }
    }

    关于c# - 为什么在finally block 中休眠时线程不被中断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7064811/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com