【问题标题】:Dangers of C# MTA thread creating STA COM objectC# MTA 线程创建 STA COM 对象的危险
【发布时间】:2013-12-01 03:18:17
【问题描述】:

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

通过我的研究,我发现您不应该在 MTA 线程上实例化 STA COM 组件,但我找不到任何具体的文字来说明这样做的危险是什么,或者这可能是我不明白的事实COM 线程单元很好。

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

编辑

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

IDbConnection connection;

//Code omitted for brevity where connection is initialized

connection.ConnectionString = myConnectionString;

异常类型:System.NullReferenceException 消息:对象 引用未设置为对象的实例。数据: System.Collections.ListDictionaryInternal TargetSite:无效 ConnectionString_Set(System.String) 在 System.Data.OracleClient.OracleConnection.ConnectionString_Set(字符串 值)在 System.Data.OracleClient.OracleConnection.set_ConnectionString(字符串 值)

【问题讨论】:

  • 所有这些对象都存在于同一个线程上——当您第一次在 MTA 单元中创建 STA 组件时,COM 运行时已经为此目的创建了一个 STA 线程。对这些组件中的任何一个的任何调用都会被编组到该 STA 线程,在那里执行(以先到先服务的方式),并且任何结果都被编组回调用者的 MTA 线程。这种并发丢失是否是您设计中的问题,由您决定。
  • 我对真正的并发问题更好奇,因为线程在内存方面相互踩踏而发生奇怪的事情。在这一点上,缺乏并发性不是问题。我只是想确保程序不会崩溃。
  • 问题很可能出在“为简洁起见省略代码”的某个地方。 connection 在您尝试分配给它的 ConnectionString 属性时为空,因此它毕竟没有被初始化,尽管您保证相反。找出原因。
  • 真的没有那么多。我会发布它。连接不为空。我已经验证不是。仅供参考,它似乎与在 MTA 而不是 STA 中运行这些线程有关。由于我进行了此更改,因此不再抛出此错误。
  • 你必须小心在你控制的 STA 线程上实例化 COM 对象——一旦 STA 线程退出,那些 COM 对象就消失了——所以如果另一个线程试图访问它们,你可以运行进入“COM 对象已与其底层 RCW 分离且无法使用”的问题。

标签: c# com


【解决方案1】:

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

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

  • COM 对象不支持编组调用的代理。这很容易发现,调用将失败并显示 E_NOINTERFACE。

  • 客户端程序员没有意识到他正在从 MTA 进行调用并忘记编组接口指针。 COM 无法阻止对进程内 COM 服务器的调用。您不能在 .NET 程序中犯此错误,CLR 将始终编组,但在其他运行时环境中很容易做到。否则,这会引起普遍的愤怒,即进行线程不安全的调用,在调试代码时工作,在生产中随机失败并且无法调试。

  • COM 作者已通过将其 ThreadingModel 声明为 Both 或 Free 来发布其组件以与 MTA 兼容。但实际上并没有对他的代码进行足够彻底的测试,编写线程安全的代码是出了名的困难。在 [ComVisible] .NET 类中尤其危险,因为它们会自动注册为 Both,而且很容易完全忘记针对该承诺测试代码。

您的 sn-p 太难以理解,无法拨打电话,但可能是第四个子弹的候选人。否则看起来根本不涉及任何 COM。像 Oracle 这样的数据提供者通常是免费线程的,并经过数十万程序员的彻底测试。

【讨论】:

    猜你喜欢
    • 2014-02-22
    • 2015-03-03
    • 1970-01-01
    • 1970-01-01
    • 2011-01-11
    • 1970-01-01
    • 2011-12-25
    • 2011-04-13
    • 1970-01-01
    相关资源
    最近更新 更多