1

有没有办法至少推迟托管应用程序的终止(几十毫秒)并设置一些共享标志以让其他线程有机会优雅地终止(SO线程本身显然不会进一步执行任何事情)?我正在考虑为此使用 JIT 调试器或 CLR 托管 - 如果有人之前尝试过,我很好奇。

为什么我想做这么错的事?:

没有太多细节——想象一下这个类比——你在赌场赌轮盘赌,突然发现轮盘赌是不可靠的假货。因此,您想立即离开赌场,但可能想先从赌桌上取回您的赌注。不幸的是,我不能为此利用单独的流程,因为有非常严格的性能要求。

试过但没有用:

StackOverflowException 的 .NET 行为(以及 MSDN 上的矛盾信息)已经在 SO 上讨论过多次 - 快速总结一下:

HandleProcessCorruptedStateExceptionsAttribute(例如在 appdomain 未处理的异常处理程序上)不起作用

ExecuteCodeWithGuaranteedCleanup不起作用

legacyUnhandledExceptionPolicy不起作用

可能很少有其他尝试如何处理 StackOverflowExceptions - 但似乎很明显,CLR 终止了整个过程,正如Hans Passant在这个很好的答案中提到的那样。

考虑尝试:

  • JIT 调试器 - 冻结异常线程,设置一些共享标志(可能在固定位置)并在短时间内解冻其他线程。
  • CLR 托管和设置未处理的异常策略

你还有别的想法吗?或者这两种方式的任何经验(成功/不成功)?

4

2 回答 2

4

对于您的赌场类比来说,“假”这个词并不完全正确。发生了 9 级地震,赌场大楼连同轮盘赌桌,剩下的筹码和玩家消失在巨大的烟尘中。

在 SOE 之后运行代码的唯一方法是远离那个赌场,它必须在另一个进程中运行。启动行为不端程序的“守卫”进程,它可以使用 Process.ExitCode 来检测崩溃。它将是 -1073741571 (0xc00000fd)。进程状态消失了,您必须使用一种 .NET 进程外互操作方法(如 WCF、命名管道、套接字、内存映射文件)来使保护进程知道需要处理的事情完成清理。这需要是事务性的,您无法推断崩溃发生的确切时间点,因为它可能在更新警卫时已经死亡。

请注意,这很少值得付出努力。因为 SOE 与日常流程中止几乎没有区别。就像被任务管理器杀死一样。或者机器断电。或者受到地震的影响:)

于 2014-07-24T09:12:53.463 回答
3

AStackOverflowException是运行时无法从中恢复的直接且严重的异常 - 这就是为什么您无法捕获它,或从中恢复,或其他任何事情。为了运行另一种方法(无论是清理方法还是其他方法),您必须能够为该方法创建一个堆栈框架,并且堆栈已经满了(这就是StackOverflowException手段!)。你不能运行另一个方法,因为运行一个方法是首先导致异常的原因!

不过幸运的是,这种异常总是由程序结构引起的。您应该能够诊断并修复代码中的错误:当您收到异常时,您会在调用堆栈中看到一个或多个方法无限循环地循环。您需要确定错误逻辑是什么并修复它,这比尝试修复无法修复的异常要容易得多。

于 2014-07-24T08:46:00.957 回答