线程安全如何是System.Reflection.Emit?

时间:2014-07-11 10:32:38

标签: c# .net thread-safety reflection.emit

我用动态代码生成和System.Reflection.Emit弄湿了脚。一切似乎都非常简单明了,但有一个问题我无法在网上找到答案。

使用AssemblyBuilder构建动态程序集时,可以创建一个类型,然后立即开始使用它。如果以后你需要在程序集中添加另一种类型,你也可以这样做,并且一切正常(据我所知)。

但是如果有两个线程试图为该程序集构建类型呢?或者如果一个现成的类型已经被使用,而另一个正在制作中呢?是否会有任何冲突或竞争条件?

已添加:好的,我认为有必要提供更多信息。

我正在使用Reflection.Emit做的是在运行时动态实现接口。基本上我有类似的东西:

class MagicClass
{
    public static T GetImplementation<T>();
}

T需要是一个接口(以及其他一些不相关的要求)。

每个接口只有一个实现,该实现只有一个实例。他们都是线程安全的单身人士。

因此,当一个新的,迄今为止看不见的接口的请求进入时,我实现它,创建一个实例,然后将其永久缓存(这里定义为“直到我的程序停止”)。

然而,这将在ASP.NET Web应用程序中完成,因此我们有许多线程一直在请求接口。性能很重要,我正在试图弄清楚我能承受多少多线程。

很明显,单个接口只能由单个线程实现。但是我可以同时在两个不同的线程中实现两个不同的接口吗?我想答案是 - “最好不要”。

好的,所以我可以添加一个锁,只有一个线程同时执行一个实现。这将照顾建筑商互相干扰。但是之前实现的接口呢?其他线程在我们制作新线程的同时使用它们。我猜他们没问题,除非他们试图在他们自己的集会上使用某种反思?

当然,我可以制定一个按程序组装的每个接口实现策略,但这样可以快速地将“已加载模块”调试器窗口发送垃圾邮件。此外,我不知道有100个装载组件会有什么性能影响(但我怀疑它们会很好)。

已添加2:是的,我的语言一定有问题,因为人们似乎没有得到它。让我试一下代码示例:

var object1 = MagicClass.GetImplementation<I1>();
DoSomethingInAnotherThread(object1);
var object2 = MagicClass.GetImplementation<I2>();

DoSomethingInAnotherThread(object1)MagicClass.GetImplementation<I2>()之间是否存在与线程相关的错误?

我们可以假设:

  • DoSomethingInAnotherThread(object1)不会致电MagicClass.GetImplementation<T>()
  • DoSomethingInAnotherThread(object1)不会在object1上使用反射,object1本身也不会使用反射。

基本上,问题是 - 对object1.SomeMethod()的无辜调用是否会爆炸,因为程序集正在另一个线程上进行重组。

3 个答案:

答案 0 :(得分:7)

唯一声明的注释是&#34;此类型的任何公共静态(在Visual Basic中为Shared)成员都是线程安全的。任何实例成员都不能保证是线程安全的。&#34;,所以我们不能假设。

以下是通过检查IL的完全实现细节,除了轶事之外不能用于任何其他内容。

检查DefineDynamicModule,它使用lockDefineType也是如此 - 事实上,它使用与父程序集构建器相同的SyncLock

TypeBuilder内的某些内容(DefineEventDefineMethodDefineField等);但有些内容,例如DefineCustomAttribute最终会出现在extern代码中,所以我们无法告诉您;但是,我在途中看不到lock,并且它没有通过extern方法锁定。

总体而言,看起来似乎已经考虑过线程安全性,但很可能他们并不想要正式保证它。看起来最常见的东西应该没问题,特别是如果你从来没有多个线程工作在同一类型上。

重点:这完全是针对具体实现的,并且我们没有&#34;这个用例保证可以正常工作,但是没有考虑过#34;。

我倾向于保持简单,个人;一个建造者(每个组装)通常很好。

答案 1 :(得分:5)

未指定。

每当您使用非显式记录的代码是线程安全的时候,您就必须做出选择。权衡不锁定的成本,弄错并让您的代码以完全随机的间隔以无法诊断的方式崩溃。对付锁定的成本并确保永远不会出错,只是有点慢。

哪里&#34;有点慢&#34;是你必须知道做出正确选择的事情。在这种情况下,这是一个简单的方法,构建一个方法最多需要几微秒。您放置它的锁是将被争议。如果无论如何,那么所引起的延迟对任何人都是不可观察的。线程上下文切换或页面错误,导致代码运行速度变慢的正常事情需要花费更多时间。

拿锁。你永远不必抱歉。

答案 2 :(得分:0)

  

基本上,问题在于是否可以对object1.SomeMethod()进行无害的调用,因为在另一个线程上重组了程序集。

根据Castle.Core软件包的使用经验,该软件包使用System.Reflection.Emit生成类型,我很确定,它总是可以并且有时会爆炸。我通常会看到的症状是,当您尝试使用一种生成的类型时,会得到TypeLoadExceptionBadImageFormageException