【问题标题】:Releasing COM objects in a background thread在后台线程中释放 COM 对象
【发布时间】:2012-03-06 03:35:28
【问题描述】:

扩展至Release COM Object in C#

我注意到保存和释放 MailItem 是一项耗时的任务。那么,执行以下操作是否安全? (下面是伪代码)

Thread 1 (main thread)
- Open 10 (different .msg files) - MailItems [List<MailItem> items]
- user works on them and want to save and close all of them with one click.

- On_save_All_click (runs on main thread)
- Do
- toBeClearedList.addAll(items);
- items.clear() [so that main thread cannot access those items]
- BG_Thread.ExecuteAsyn(toBeClearedList);
- End

Thread 2 (background thread) (input - List<MailItems>) 
- foreach(MailItem item in input)
    item.save();
    System.Runtime.InteropServices.Marshal.ReleaseComObject(item)
- done

我写了几个测试,看起来它工作正常;只是想知道这样做是否安全? “在与创建它的线程不同的线程中释放 COM 对象”

谢谢

卡雷菲尔

【问题讨论】:

    标签: c# com outlook


    【解决方案1】:

    在非托管代码 (C/C++) 中使用 COM 时,规则非常严格:您只能在获取对象的同一单元中调用接口上的方法。因此,如果您在 STA 线程上获得接口指针,则仅允许该线程调用任何方法。如果您在 MTA 线程上获得接口指针,则只有同一 MTA 中的其他线程可以使用该指针。跨公寓的任何其他用途都需要将接口指针编组到另一个公寓。

    然而,那是一个未受破坏的世界。 .Net 在 COM 之上添加了一个完整的层,它隐藏了许多这些低级细节,并且在大多数情况下,一旦你掌握了一个接口,你就可以在线程之间尽可能多地传递该接口,而无需不必担心旧的线程规则。这里发生的情况是,它实际上是在传递对称为“运行时可调用包装器”(RCW) 的对象的引用,并且它正在管理底层 COM 接口,并相应地控制对它的访问。 (它承担了维护 COM 单元规则的负担,这样您就不必这样做了,这就是为什么旧的 COM 线程规则似乎不适用于 .Net:它们确实适用,只是被隐藏了你。)

    因此您可以安全地从另一个线程调用 Release 或其他方法:但请注意,如果原始线程是 STA,那么调用这些方法将导致底层 RCW 将调用编组回原始拥有线程,以便它仍然维护下层 COM 规则。因此,使用单独的线程最终可能实际上不会为您带来任何性能!

    一些值得一读的文章在这里填写了一些细节:

    【讨论】:

      【解决方案2】:

      如果我记得我的 COM 正确(我一直讨厌那种技术,太复杂了),如果 COM 对象是单线程的(也就是说,属于单线程单元),从另一个线程释放它是'不会对你有任何好处 - 它只会在你的主线程中执行实际的发布代码。

      会看到你的代码和在一个循环中从主线程释放对象之间的一点区别。如果您在一个循环中释放对象,您的 UI 将无法响应,直到您释放所有消息。通过使用辅助线程,您的 UI 线程将释放一条消息,然后处理其他事件,然后释放另一条,依此类推。您可以通过向自己发送消息(如果您有 WPF 应用程序,则使用 Dispatcher)来获得相同的效果,并避免使用另一个线程。

      【讨论】:

      • 正如你所说,我唯一想要实现的是“响应 UI”。只要可以安全地启动另一个线程并安全地释放这些 COM 对象(没有任何不需要的异常),我就很好。 (我会继续测试)
      猜你喜欢
      • 1970-01-01
      • 2016-08-31
      • 2011-09-15
      • 2020-09-10
      • 2015-09-25
      • 2012-09-17
      • 2012-03-05
      • 2014-02-14
      相关资源
      最近更新 更多