【问题标题】:Critical section vs Thread.Abort()临界区与 Thread.Abort()
【发布时间】:2019-11-09 10:05:28
【问题描述】:

这是我经常用来执行锁定的模式:

private IDisposable GetLock()
{
    _lock.Wait();
    return new Disposable(()=> _lock.Release());
}

我在这段代码中看到的唯一问题是 Thread.Abort(),它可以进入 _lock.Wait() 和 return 语句之间,使锁处于不一致状态。我试图通过将其保存到变量中来避免这种情况:

private IDisposable GetLock()
{
    var l = _lock;
    l.Wait();
    try
    {
       var result = new Disposable(()=> _lock.Release());
       l = null;       //<- I need to make this atomic, unabortable section
       return result;  //<- I need to make this atomic, unabortable section
    }
    finally
    {
       l?.Release();
    }
}

但中止有时仍会使此部分陷入僵局。 怎样才能保护这部分免受 Thread.Abort() 的影响?

【问题讨论】:

  • 你刚刚重新发明/编码了锁块。
  • 文件类实现 IDisposeable。你通过调用 dispose 来释放它。同样的改造,只是使用而不是锁定。
  • 数据库负责管理它打开的任何连接。最新的超时,它会这样做。您的要求至少没有明确传达。
  • 所以我确定我是对的。您假设某人 - 没有合理的理由 - 会仅为破坏您的代码而编写代码。它会通过在 Null Check 和 dispose 调用之间插入异常来进行破坏吗?而这一切会在发布期间发生,没有明显的原因? |因为那个级别的破坏,不在你的手中。您不妨尝试保护您的代码免受断电或 RAM 故障的影响。
  • 所以你的想法是 ThreadAbort 可以在 finally 块期间引发并且没有针对这种奇怪情况的保护?

标签: c#


【解决方案1】:

你不应该使用Thread.Abort()。它主要意味着错误的代码结构。唯一的例外是,如果您必须使用有缺陷的第三方库(您无法更改哪些代码),您可以终止挂起的代码。

放开Thread.Abort(),你的生活会轻松很多。

只需使用lock 语句即可。


中止线程会导致任意行为,这是一个常见的规则,应始终避免。

【讨论】:

  • 我知道,这很可悲,但是如果您编写 API,没有人可以保护您免受此伤害。有人使用您的代码,而您只想编写锁原语。如果由于系统开发方式而导致死锁是糟糕的原始数据 - 没有人会使用它。
  • 当然可以,但是您不应该解决不存在的问题。您不对使用您的 API 的开发人员的无知或缺乏经验负责。中止线程会导致任意行为,这是一个常见的规则,应该始终避免。
  • 如果需要中止一个动作,你应该内置一个。比如设置一个WaitHandle,你将检查它或CancellationToken
  • 是的,但是有一个问题,为什么在 Mutex.Enter() 中不会发生死锁,这当然是原始编写的某种方式来避免在中止时发生这种情况。关于可能的 Thread.Abort().
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-10-17
  • 2013-03-26
  • 2013-04-07
  • 2021-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多