C# COM、STA和多线程
我有这个遗留的第三方COM DLL。我将其注册到注册表,并将RCW添加到我的.NET/C#控制台应用程序中。注册表将COM的线程模型显示为单元。我的应用程序的全部目的是使用多线程并发提交多个请求并接收对此COM服务器的响应 我正在使用SmartThreadPool进行线程管理,现在在每个线程中,我都在为COM查找/请求提交步骤创建新对象。但是,如果我查看COM服务器日志,请求仍然是按顺序提交/处理的 问题在哪里 因此,我认为问题在于COM是单元/STA配置的。 但我的最终目标是让它发挥作用,所以我的问题C# COM、STA和多线程,c#,.net,visual-studio,com,C#,.net,Visual Studio,Com,我有这个遗留的第三方COM DLL。我将其注册到注册表,并将RCW添加到我的.NET/C#控制台应用程序中。注册表将COM的线程模型显示为单元。我的应用程序的全部目的是使用多线程并发提交多个请求并接收对此COM服务器的响应 我正在使用SmartThreadPool进行线程管理,现在在每个线程中,我都在为COM查找/请求提交步骤创建新对象。但是,如果我查看COM服务器日志,请求仍然是按顺序提交/处理的 问题在哪里 因此,我认为问题在于COM是单元/STA配置的。 但我的最终目标是让它发挥作用,所以
公共类启动
{
公共静态void Main(字符串[]args)
{
开始处理();
}
私有静态void StartProcessing()
{
CoreComator pcr=新CoreProcessor();
pcr.start();
}
}
公共类核心处理器
{
公共静态手动重置事件已全部完成;
公共静态int NumberOfActiveThreads;
私有SmartThreadPool TPool=新的SmartThreadPool();
公开作废开始()
{
IEnumerable LstRequests=FileIO.GetAllRequestFileNames();
NumberOfActiveThreads=LstRequests.Count();
IsAllDone=新手动重置事件(假);
foreach(LstRequests中的var reqName)
{
ReqInfo req=new ReqInfo(){RequestPath=reqName;};
TPool.QueueWorkItem(新的WorkItemCallBack(req.ProcessRequest));
}
如果(NumberOfActiveThreads>0)
IsAllDone.WaitOne();
}
}
公共类请求信息
{
公共字符串请求路径;
public void ProcessRequest()
{
ABC_COM_Request req=新的ABC_COM_XMLUTIL().CreateRequest();
ABC_COM_Server svr=新的ABC_COM_ServerLookup().lookup(“serverhostname”,1099);
ABC\u COM\u响应响应=svr.提交(请求);
if(联锁减量(参考CoreProcessor.NumberOfActiveThreads)==0)
CoreProcessor.IsAllDone.Set();
}
}
如果您只有COM组件,而它是STA组件,那么您无法同时调用该组件服务的实例
但是,这并不妨碍您实例化组件的多个实例并调用多个实例。为此,您可能需要考虑使用和获取组件的实例。
请注意,仅仅因为COM组件正在与之交谈的服务能够并发处理请求,这是一个与客户端并发处理对它的调用的能力完全不同的问题
假设您可以获得代码,那么就不可能说出在MTA或免费线程中运行它需要什么(后者更好);我们不知道实现细节或存储的状态(甚至不知道API是什么样子)
如果组件所做的只是发送请求和处理响应,而不存储状态,那么应该相当容易,只需切换单元即可
但是,有两个原因可能会导致组件损坏:
1) 组件有大量的状态,STA是确保状态不会被并发调用破坏的一种方法;在这种情况下,使组件MTA/free线程化的工作将很困难,因为您必须保护所有内容,即使这样,您也可能无法从所有必须进行的并发性检查中获得任何好处(尽管您可能会找到一种方法将代码转换为.NET代码,以一种易于线程安全的方式)
2) 该组件是用VB6或不支持MTA/自由线程组件的语言编写的;在这种情况下,无法更改单元模型,您必须拥有多个实例或转换为线程安全的.NET。您可能需要创建多个STA线程,每个STA线程都有自己的消息循环(*),每个STA线程都有自己的单元线程COM对象实例 您可以通过调用来设置线程的单元状态
(*)如果需要封送来自其他线程的调用,则需要消息循环。“单元”表示COM服务器不支持线程。从工作线程发出的所有调用都将由COM自动封送到创建COM对象的线程,以确保以线程安全的方式使用它。您将无法获得并发性。对此没有解决方法,不支持线程的代码不能用于支持线程。从你之前的问题中你已经知道了这一点。汉斯,一如既往,非常清晰准确,谢谢。但实际上我是第一次使用com,所以很困惑。我猜COM本身是在非托管进程中执行的,我们通过代理(RCW)使用它。所以,当多个线程使用同一个COM时,您的意思是我们的代理仍然在发送并行调用,un mana
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();
}
}