COM, STA and multithreading

I have this obsolete third-party COM library. I registered it in the registry and added RCW to the .NET / C # console application. The registry shows the Threading Model for COM as Flat . The whole purpose of my application is to send multiple requests at once and receive responses to this COM server using multithreading.

I use SmartThreadPool to control threads, and now in each thread I create new objects for COM search and query steps. However, if I look at COM SERVER LOG, requests are sent / processed sequentially.

Where is the problem?

So, I believe that the problem is that COM is configured to work in the apartment / STA . But my ultimate goal is to make it work, so my questions,

  • Suppose all I have is an STA COM DLL file, are there any workarounds that I can get my requests to be processed in parallel?

  • Please note that when two instances of my console application are launched simultaneously, the logs in the destination server (with which the COM-DLL really connects and works) actually show that requests from two instances are processed in parallel in two different sessions. Thus, the final application is designed to support parallel processing. (And I guess this is a childish question) Suppose I can get COM code, will it just be to get it to support MTA?

[It really gets too confusing and I get nuts! Please note that each of the streams creates its own set of new objects from the COM-DLL file for COMServer search, request, send, etc.]

Application code

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(); } } 
+4
source share
2 answers

If all you have is a COM component and an STA component, then you can do nothing to make a service instance of this component call at the same time .

However, this does not stop you from creating multiple instances of the component and making calls to multiple instances. To this end, you can consider using a pool of COM + objects and get your component instances this way.

Please note that only because the service with which the COM component is talking can process requests at the same time is a problem that is completely separate from the client's ability to process calls to it at the same time.

Assuming you can get the code, it's impossible to say what it takes to get it working in MTA or free-threaded (the latter is preferable); we don’t know the details of the implementation or the state that is stored (or what looks like an API).

If the entire component executes, it sends requests and processes the responses without saving the state, then this should be quite simple, it is just a matter of switching the apartment.

However, there are two reasons why a component can be an STA:

1) The component has many states, and the STA is a way to make sure that the state has not been corrupted by simultaneous calls; in this case, your work on creating the MTA / free-threaded component will be difficult, since you will have to protect everything, and even then you will not get any benefits due to all the concurrency checks that may occur (although you can find a way to convert the code to .NET code that is easily thread safe).

2) The component was written in VB6 or a language that does not support the MTA / free-threaded components; in this case, it is impossible to change the apartment model, and you will have to either have several instances or make a conversion to .NET, which is thread safe.

+2
source

You probably need to create several STA threads, each with its own message loop (*), and each with its own threaded COM object instance.

You can set the state of the thread flat by calling Thread.SetApartmentState .

(*) A message loop is needed if you need to route calls from another thread.

+1
source

Source: https://habr.com/ru/post/1379136/


All Articles