COM, STA和多线程

本文关键字:多线程 STA COM | 更新日期: 2023-09-27 18:12:53

我有这个遗留的第三方COM DLL。我将它注册到注册表中,并将RCW添加到我的。net/c#控制台应用程序中。注册表显示COM的Threading ModelApartment。我的应用程序的整个目的是并发地提交多个请求,并使用多线程接收此COM服务器的响应。

我正在使用SmartThreadPool线程管理,现在在每个线程中,我为COM查找/请求提交步骤创建新对象。然而,如果我看一下COM SERVER LOG,请求是按顺序提交/处理的。

问题在哪里?

所以,我认为问题实际上在于COM是公寓/STA配置的。但我的最终目标是让它工作,所以我的问题,

  1. 假设所有我有在我的处置是这个stapcom DLL文件,有任何-任何-任何解决方案,我可以使它并行处理我的请求?

  2. 考虑这样一个事实,当我并行运行控制台应用程序的两个实例时,最终服务器机器(COM DLL实际上与之连接和工作)中的日志实际上显示来自两个实例的请求在两个不同的会话中并行处理。因此,最终的应用程序都是为了支持并行处理而设计的。(我猜这是一个幼稚的问题)假设我能得到COM代码,让它支持MTA会很容易吗?

[这真是太令人困惑了,我要疯了!请注意,每个线程都是从COM DLL文件中创建自己的一组新对象,用于COMServer查找,请求,提交等。

应用程序代码
public class start
{
    public static void Main(string[] args)
    {
         StartProcessing();
    }
    private static void StartProcessing()
    {
        CoreProcessor pcr = new CoreProcessor();
        pcr.start();
    }
}
public class CoreProcessor
{
    public static ManualResetEvent IsAllDone;
    public static int NumberOfActiveThreads;
    private SmartThreadPool TPool = new SmartThreadPool();
    public void start()
    {
        IEnumerable<string> LstRequests = FileIO.GetAllRequestFileNames();
        NumberOfActiveThreads = LstRequests.Count();
        IsAllDone = new ManualResetEvent(false);
        foreach(var reqName in LstRequests)
        {
            ReqInfo req = new ReqInfo(){RequestPath = reqName;};
            TPool.QueueWorkItem(new WorkItemCallBack(req.ProcessRequest));
        }
        if(NumberOfActiveThreads  > 0)
            IsAllDone.WaitOne();
    }
}
public class ReqInfo
{
    public string RequestPath;
    public void ProcessRequest()
    {
         ABC_COM_Request req = new ABC_COM_XMLUTIL().CreateRequest();
         ABC_COM_Server svr = new ABC_COM_ServerLookup().lookup("serverhostname", 1099);
         ABC_COM_Response resp = svr.submit(req);
         if (InterLocked.Decrement(ref CoreProcessor.NumberOfActiveThreads) == 0)
                     CoreProcessor.IsAllDone.Set();
    }
}

COM, STA和多线程

如果你所有的是COM组件,它是一个STA组件,那么你不能做任何事情使该组件的实例服务调用并发

但是,这并不妨碍您实例化组件的多个实例并调用多个实例。为此,您可能需要考虑使用COM+对象池,并以这种方式获取组件的实例。

请注意,仅仅因为COM组件正在与之通信的服务能够并发地处理请求,这是一个与客户端并发地处理对它的调用的能力完全分离的问题。

假设您可以得到代码,不可能说需要什么才能使它在MTA或自由线程中运行(后者更可取);我们不知道实现细节或存储的状态(甚至不知道API是什么样子的)。

如果所有组件所做的是发送请求和处理响应而不存储状态,那么它应该相当容易,这只是切换公寓的问题。

然而,组件可能是STA有两个原因:

1)组件有很多状态,STA是一种确保状态不会被并发调用破坏的方法;在这种情况下,你的工作,使组件MTA/自由线程将是困难的,因为你必须保护一切,即使这样,你可能不会获得任何好处,由于所有的并发性检查,你可能不得不做(尽管你可能找到一种方法,将代码转换为。net代码,在一种方式,很容易是线程安全的)。

2)组件是用VB6或不支持MTA/自由线程组件的语言编写的;在这种情况下,不可能更改公寓模型,您必须有多个实例或将其转换为线程安全的。net。

您可能需要创建多个STA线程,每个线程都有自己的消息循环(*),每个线程都有自己的公寓线程COM对象实例。

你可以通过调用thread . setapartmentstate设置线程的公寓状态。

(*)如果需要封送来自另一个线程的调用,则需要消息循环。