COM,STA和多线程

时间:2011-11-01 13:17:12

标签: c# .net visual-studio com

我有这个传统的第三方COM DLL。我将它注册到注册表并将RCW添加到我的.NET / C#控制台应用程序中。注册表将COM的线程模型显示为公寓。我的应用程序的整个目的是同时提交多个请求并使用多线程接收对此COM服务器的响应。

我正在使用SmartThreadPool进行线程管理,现在在每个线程中我都在为COM查找/请求提交步骤创建新对象。但是,如果我查看COM SERVER LOG,则会按顺序提交/处理请求。

问题出在哪里?

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

  1. 假设我所拥有的只是这个STA COM DLL文件,是否有任何任何解决方法我可以让它并行处理我的请求?

  2. 考虑一下这个事实,当我并行运行我的控制台应用程序的两个实例时,最终服务器计算机中的日志(COM DLL实际连接并正常工作)实际上表明来自两个实例的请求是并行处理的在两个不同的会议中。因此,最终的应用程序都是为了支持并行处理。 (我想这是一个幼稚的问题)假设我能够掌握COM代码,是不是很容易让它支持MTA?

  3. [这真的太混乱了,我疯了!请注意,每个线程都在从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();
        }
    }
    

2 个答案:

答案 0 :(得分:2)

如果您只拥有COM组件并且它是一个STA组件,那么您无法做任何事情来同时调用该组件服务的实例

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

请注意,仅仅因为COM组件正在与之通信的服务能够同时处理请求,这是一个完全独立于客户端同时处理 it 调用的能力的问题。

假设您可以接受代码,那么就无法说明在MTA或自由线程中运行它需要什么(后者更可取);我们不知道实现细节或存储的状态(或者API甚至是什么样的)。

如果所有组件都在发送请求并处理响应而不存储状态,那么它应该相当容易,只需要切换公寓。

但是,组件可能是STA的原因有两个:

1)组件具有很多状态,STA是一种确保状态不会因并发调用而损坏的方法;在这种情况下,您制作组件MTA /自由线程的工作将很困难,因为您必须保护所有内容,即便如此,由于您可能必须进行的所有并发检查,您可能无法获得任何好处(尽管你可能会找到一种方法,以一种易于线程安全的方式将代码转换为.NET代码。

2)组件是用VB6编写的,或者是不支持MTA /自由线程组件的语言;在这种情况下,无法更改公寓模型,您将不得不拥有多个实例或转换为线程安全的.NET。

答案 1 :(得分:1)

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

您可以通过调用Thread.SetApartmentState来设置线程的公寓状态。

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