C#MTA线程创建STA COM对象的危险

我目前正在查看我们在.Net Framework 2.0 Windows服务(C#)中遇到的问题,该服务具有运行X个MTA线程以访问COM组件。 每个线程初始化它自己的com组件对象的实例。 com组件对象没有任何UI元素。 它只是业务逻辑,它与sql server数据库和带有com接口的C#dll进行通信,而com接口又进行套接字通信并访问同一个sql server数据库。

通过我的研究,我发现你不应该在MTA线程上实例化STA COM组件,但我找不到任何特定的文本来说明这是什么危险或者可能是因为我不理解COM线程公寓那很好。

上面描述的模型会出现并发问题吗? 即使每个MTA线程都在创建自己的STA COM对象?

编辑

我们实际遇到的问题是对象引用未设置为后续代码块中连接字符串的setter中的对象错误的实例。 这发生在c ++ COM对象调用的C#COM对象中:

IDbConnection connection; //Code omitted for brevity where connection is initialized connection.ConnectionString = myConnectionString; 

exception类型:System.NullReferenceException消息:未将对象引用设置为对象的实例。 数据:System.Collections.ListDictionaryInternal TargetSite:System.Data.OracleClient.OracleClient.OracleClient.OracleConnection.set_ConnectionString(String value)中System.Data.OracleClient.OracleConnection.ConnectionString_Set(String value)处的Void ConnectionString_Set(System.String)

从MTA拨打电话时有四种基本的“危险”:

  • COM对象是公寓线程,非常常见,因此必须将调用封送到拥有该对象的公寓。 技术上正确的“STA COM”措辞。 这是昂贵的 ,对小方法的编组调用通常要慢10,000倍。

  • COM对象不支持编组调用的代理。 这很容易找到,调用将失败E_NOINTERFACE。

  • 客户端程序员没有意识到他正在从MTA拨打电话并忘记编组接口指针。 COM无法阻止对进程内COM服务器的调用。 你不能在.NET程序中犯这个错误,CLR总是编组,但在其他运行时环境中很容易做到。 否则会调用发生线程不安全调用的常见愤怒,在调试代码时起作用,在生产中随机失败并且无法调试。

  • COM作者通过将ThreadingModel声明为Both或Free来发布他的组件以与MTA兼容。 但实际上并没有彻底地测试他的代码,编写线程安全的代码是非常困难的。 在[ComVisible] .NET类中特别危险,因为它们会自动注册为Both,并且很容易完全忘记根据该承诺测试代码。

您的代码片段太难以理解,无法拨打电话,但可能是第4个子弹的候选人。 它看起来根本不像任何COM。 像Oracle这样的数据提供者通常是由数十万程序员自由编程和测试的。