gpt4 book ai didi

c# - .NET 中是否存在僵尸?

转载 作者:IT王子 更新时间:2023-10-29 03:27:51 25 4
gpt4 key购买 nike

我正在与队友讨论锁定 .NET 的问题。他是一个非常聪明的人,在低级和高级编程方面都有广泛的背景,但他在低级编程方面的经验远远超过我。不管怎样,He 认为,如果可能的话,应该避免在预计会承受重负载的关键系统上使用 .NET 锁定,以避免“僵尸线程”导致系统崩溃的可能性很小。我经常使用锁定,但我不知道“僵尸线程”是什么,所以我问了。我从他的解释中得到的印象是,僵尸线程是一个已终止但仍以某种方式保留某些资源的线程。他举了一个僵尸线程如何破坏系统的例子,一个线程在锁定某个对象后开始执行某个过程,然后在释放锁之前的某个时刻终止。这种情况有可能使系统崩溃,因为最终,尝试执行该方法将导致所有线程都在等待访问永远不会返回的对象,因为使用锁定对象的线程已死。

我想我明白了这个要点,但如果我偏离了基地,请告诉我。这个概念对我来说很有意义。我并不完全相信这是 .NET 中可能发生的真实场景。我以前从未听说过“僵尸”,但我确实认识到,在较低级别深入工作的程序员往往对计算基础知识(如线程)有更深入的了解。然而,我确实看到了锁定的值(value),而且我已经看到许多世界级的程序员利用锁定。我自己评估这个的能力也有限,因为我知道 lock(obj) 语句实际上只是语法糖:

bool lockWasTaken = false;
var temp = obj;
try { Monitor.Enter(temp, ref lockWasTaken); { body } }
finally { if (lockWasTaken) Monitor.Exit(temp); }

并且因为 Monitor.EnterMonitor.Exit 被标记为 extern。似乎可以想象 .NET 会进行某种处理,以保护线程免受可能产生此类影响的系统组件的影响,但这纯粹是推测,可能只是基于我从未听说过“僵尸线程”这一事实前。所以,我希望我能在这里得到一些反馈:

  1. “僵尸线程”的定义是否比我在这里解释的更清晰?
  2. .NET 上会出现僵尸线程吗? (为什么/为什么不?)
  3. 如果适用,我如何在 .NET 中强制创建僵尸线程?
  4. 如果适用,我如何在不冒 .NET 僵尸线程场景风险的情况下利用锁定?

更新

我在两年多前问过这个问题。今天这件事发生了:

Object is in a zombie state.

最佳答案

  • “僵尸线程”的定义是否比我在这里解释的更清晰?

对我来说似乎是一个很好的解释 - 一个线程已经终止(因此不能再释放任何资源),但其资源(例如句柄)仍然存在并且(可能)导致问题。

  • .NET 上会出现僵尸线程吗? (为什么/为什么不?)
  • 如果适用,我如何在 .NET 中强制创建僵尸线程?

他们肯定会,看,我做了一个!

[DllImport("kernel32.dll")]
private static extern void ExitThread(uint dwExitCode);

static void Main(string[] args)
{
new Thread(Target).Start();
Console.ReadLine();
}

private static void Target()
{
using (var file = File.Open("test.txt", FileMode.OpenOrCreate))
{
ExitThread(0);
}
}

这个程序启动了一个线程Target,它打开一个文件,然后立即使用ExitThread 杀死自己。 . 生成的僵尸线程永远不会释放“test.txt”文件的句柄,因此该文件将保持打开状态直到程序终止(您可以使用进程资源管理器或类似工具进行检查)。 “的句柄” test.txt”在 GC.Collect 被调用之前不会被释放 - 事实证明创建一个泄漏句柄的僵尸线程比我想象的还要困难)

  • 如果适用,我如何在不冒 .NET 僵尸线程场景风险的情况下利用锁定?

不要做我刚刚做的事!

只要您的代码能够正确地自行清理(使用 Safe Handles 或使用非托管资源时的等效类),并且只要您不特意以奇怪而美妙的方式杀死线程(最安全的方法就是永远不要杀死线程 - 让它们正常终止自己,或者在必要时通过异常终止),你将拥有类似于僵尸线程的唯一方法是如果某些东西出现了非常错误(例如,CLR 中出现问题)。

事实上,创建一个僵尸线程实际上出奇地困难(我不得不 P/Invoke 到一个函数中,该函数在文档中基本上告诉您不要在 C 之外调用它)。例如,以下(糟糕的)代码实际上并没有创建僵尸线程。

static void Main(string[] args)
{
var thread = new Thread(Target);
thread.Start();
// Ugh, never call Abort...
thread.Abort();
Console.ReadLine();
}

private static void Target()
{
// Ouch, open file which isn't closed...
var file = File.Open("test.txt", FileMode.OpenOrCreate);
while (true)
{
Thread.Sleep(1);
}
GC.KeepAlive(file);
}

尽管犯了一些非常可怕的错误,“test.txt”的句柄仍然在 Abort 被调用时关闭(作为 file 终结器的一部分,它在幕后使用 SafeFileHandle 包装其文件句柄)

C.Evenhuis answer 中的锁定示例当线程以非奇怪的方式终止时,可能是无法释放资源(在本例中为锁)的最简单方法,但这很容易通过使用 lock 语句来解决,或者将发布放在 finally block 中。

另见

关于c# - .NET 中是否存在僵尸?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20065780/

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