Thread.Abort()腐败是否已本地化?

时间:2010-07-14 08:02:49

标签: c# .net multithreading

据我所知,由于各种原因调用Thread.Abort()是错误的和错误的

  1. 可以锁定或在其他关键区域
  2. 可能在I / O操作的中途,资源无法清理
  3. 代码可以吞下ThreadAbortException
  4. 可能处于状态更改操作的中途,并使程序处于无效状态。
  5. 假设线程的Run()方法:

    1. 不使用并发原语。
    2. 不执行任何I / O.
    3. 不会吞下这样的例外。
    4. 暴露给只读API,因此无法更改程序状态。
    5. 问题:

      如果我在这样的线程上调用Abort(),那么损坏(关于腐败)是否已经本地化?在,我可以依赖我的程序,没有最近中止的线程,继续正常行为,或者是我的整个进程/ AppDomain / ??然后可能被腐蚀了?

      如果我删除假设1和2会中止()腐败被本地化为特定的并发原语和它访问的I / O资源?或者它可以向外传播吗?

      为什么我鞭打Thread.Abort()死马

      我正在编写一个胖客户端c#winforms应用程序。一个功能是用户能够在c#中编写代码,在我的域对象上实现接口,然后可以将其插入我的应用程序(代码通过codedom编译成程序集并使用反射加载);

      所以想法是用户可以写

      public class CustomComputation : IComputationThing
      {
          public void Compute(object context)
          {
              while (true) ;
          }
      }
      

      然后我可以反思生成的程序集,提取并实例化CustomComputation的实例,并调用Compute(...);非常简单的东西。

      问题是用户可以写上面的 - 无限循环,或者他决定不想等待的其他指数时间计算。

      我正在尝试调查我的选择,以便在用户编写一些无限循环(或指数时间等)代码并希望从中止时提供尽力恢复。虽然我打算要求用户遵守取消模式但最终无法保证他们会这样做。

5 个答案:

答案 0 :(得分:1)

除非您了解.NET运行时库的每个细节,否则我怀疑您实际上可以保证您的假设(特别是4和1)。违反假设4真正需要的是一个单独的静态变量......

如果您使用生成的代码,则单独的AppDomain更容易停止和卸载,与线程不同,这可以作为托管进程的正常生命周期的一部分来完成。

答案 1 :(得分:1)

Thread.Abort()肯定会污染你的AppDomain,但我相信它也会破坏整个进程的稳定性。我找不到这么快的链接。

因此,您必须在单独的(一次性)流程中运行它。

答案 2 :(得分:1)

由于用户代码是如此动态(我希望典型的开发人员在编写代码时会进行数十次测试运行),所以无论如何都要将它放在一个单独的AppDomain中,这样你就可以卸载它。如果是这样,那么腐败只会影响单独的appdomain,无论如何都会很快卸载。

现在,我实际上开始想知道如果用户代码会产生另一个线程/ appdomain会发生什么,但这是另一个问题。也许它可以通过一些权限来解决,我对它们并不熟悉。

答案 3 :(得分:1)

看看.net Terrarium项目。这是一个点对点演示应用程序,用于演示.net框架的对等功能和黑客安全性。开发人员可以匿名编写和上传AI代码来控制虚拟玻璃容器中的昆虫,该虚拟玻璃容器作为数千台机器上的对等生态系统运行。

他们使用反射来确保上传的代码是安全的:您无法执行IO,限制锁定以及静态变量。它们也限制了你被允许“思考”的时间。这个应用程序的优点应该足够好。

http://terrarium2.codeplex.com/

答案 4 :(得分:1)

如Vilx所述 - 您可以考虑将“用户”代码放在另一个AppDomain中。

事实上,自.Net 3.5以来,.Net Framework已经包含了System.AddIn命名空间,它提供了一种在单独的应用程序域(以及其他内容)中隔离“加载项”代码的简化方法。如果不需要太多的跨域通信,这将为您提供良好的隔离级别,最糟糕的情况是您拆除特定于用户代码的AppDomain。

有关详细信息,请参阅此MSDN文章和CLR-Addin team's blog

此外,尽管它没有解决所有问题,但您可以从触发Thread.Interrupt开始。这将导致以与ThreadAbortException类似的方式引发ThreadInterruptException,除了它将在代码中的定义点处发生;当线程阻塞或睡眠时,而不是绝对任何地方。它可能无助于你上面提到的紧密循环示例,但如果循环有一个Thread.Sleep(0)。

您可以随时选择自己的选择:

  • 在IComputationThing上放置一个Stop()方法,并要求用户实现它。
  • 如果一个加载项没有及时响应Stop(),请尝试一个Thread.Interrupt(并说明紧张操作者可能希望在其循环中放入一个Thread.Sleep(0)来屈服于另一个线程)
  • 如果失败,请尝试Thread.Abort,或者拆除App域(可能是后者直接)。