COM和线程安全

dav*_*d.s 6 c# com locking thread-safety

我需要将ASP.NET MVC网站与第三方COM应用程序集成.代码看起来像这样:

Type type = Type.GetTypeFromProgID(progID);
dynamic obj = Activator.CreateInstance(type);
if (!obj.DBOpenedStatus)
{
    obj.InitApplicationContext();
    //do stuff with other COM objects
}
Run Code Online (Sandbox Code Playgroud)

问题是,经过一段时间后,我开始得到的COMExceptions可能性很大,因为我从未使用过关闭该上下文obj.ReleaseApplicationContext().所以我正在考虑编写一个包装器实现,IDisposable这样我就可以在构造函数中初始化上下文,并在它被处理时释放它.但是我需要一个,lock以便当前线程仍在工作时,另一个线程不会关闭上下文.代码如下所示:

lock (_locker)
{
    using (MyComContextWrapper comContext = new MyComContextWrapper())
    {
        //do stuff with other COM objects
    }
}
Run Code Online (Sandbox Code Playgroud)

我对线程安全知之甚少,所以我问你的是:

  1. 我的方法有什么问题吗?
  2. 还有什么我应该考虑的(比如死锁或别的东西)?
  3. 你会推荐一种不同的方法吗?

编辑1:
我在注册表中查找了COM类的progID,发现ThreadingModel=ApartmentCOM应用程序使用了Single-Threaded Apartment类型.

编辑2:
COM应用程序使用系统为对象生成id,以便当这些对象持久存储在数据库中时,它们已经具有Id.该系统涉及在注册表中写入一些信息.过了一会儿这个系统出了问题,我开始收到violation of primary key constraint错误.

编辑3:
我有时会得到一个System.ArgumentNullException: Value cannot be null. Parameter name: type at Activator.CreateInstance(Type type).这可能是因为我正在尝试从另一个线程创建一个新的STA对象吗?

编辑4:
有人要求我发布完整的堆栈COMExceptions,但我担心这会让我的问题过于本地化,对我以外的任何人都没用.此外,我实际上找到了问题的原因:有一些非常罕见的情况,在使用某些com对象之前未初始化上下文并且这使系统搞砸了,但错误仅在稍后出现.所以我确保在使用任何com对象之前始终初始化上下文并且问题消失了.

我仍然对线程安全和我提出的解决方案的答案感兴趣.或者问题可能因为过于本地化而被关闭?

Sim*_*ier 2

您不需要在对象周围使用锁,因为 COM 线程的整个目的是让您在多线程环境中的生活变得更轻松和自动化(一旦您了解其用途,并且注册表正确)。

在标准托管 .NET 场景中,您也不需要执行任何特定操作,甚至释放 COM 对象也应该由垃圾收集器自动完成。所以你不需要使用模式。

话虽这么说,底层非托管 COM 对象在使用后释放时可能会工作得更好,或者您的应用程序可能由于某种原因无法真正等待 GC 发生(例如,由于 hi 使用)。在这些场景中,您可以使用Marshal.ReleaseComObjectMarshal.FinalReleaseComObject来强制释放使用过的 COM 对象,并使用包装器对象对其进行包装。