#c# #.net #visual-studio #com
#c# #.net #visual-studio #com
Вопрос:
У меня есть эта устаревшая сторонняя COM-библиотека DLL. Я зарегистрировал его в реестре и добавил RCW в свое консольное приложение .NET / C #. В реестре модель потоков для COM отображается как квартира. Вся цель моего приложения — одновременно отправлять несколько запросов и получать ответы на этот COM-сервер, используя многопоточность.
Я использую SmartThreadPool для управления потоками, и теперь в каждом потоке я создаю новые объекты для шагов поиска / отправки запросов COM. Однако, все же, если я посмотрю на ЖУРНАЛ COM-СЕРВЕРА, запросы отправляются / обрабатываются последовательно.
В чем проблема?
Итак, я считаю, что проблема заключается в том, что COM настроен как квартира / STA. Но моя конечная цель — заставить его работать, поэтому мои вопросы,
-
Предположим, что все, что у меня есть в моем распоряжении, это DLL-файл STA COM, есть ли какие-либо обходные пути, которые я могу заставить его обрабатывать мои запросы параллельно?
-
Учтите тот факт, что когда я запускаю два экземпляра моего консольного приложения параллельно, журналы на конечной серверной машине (с которой фактически подключается и работает COM DLL) фактически показывают, что запросы от двух экземпляров обрабатываются параллельно в двух разных сеансах. Таким образом, конечное приложение полностью ориентировано на поддержку параллельной обработки. (И я думаю, это детский вопрос) Предположим, я могу получить доступ к COM-коду, будет ли легко заставить его поддерживать MTA?
[Это действительно становится слишком запутанным, и я схожу с ума! Пожалуйста, обратите внимание, что каждый из потоков создает свой собственный набор новых объектов из файла DLL COM для поиска на 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();
}
}
Комментарии:
1. «Квартира» означает, что COM-сервер не поддерживает потоковую обработку. Все вызовы, которые вы выполняете из рабочих потоков, будут автоматически маршалироваться COM потоку, создавшему COM-объект, чтобы гарантировать его потокобезопасное использование. Вы не получите параллелизма. Для этого нет обходного пути, код, который не поддерживает многопоточность, не может быть создан для поддержки многопоточности. Вы уже знали об этом из своих предыдущих вопросов.
2. Ганс, как всегда, очень четкий и точный, спасибо. Но на самом деле я использую com впервые и поэтому запутался. Я предполагаю, что сам COM выполняется в неуправляемом процессе, и мы используем его через прокси (RCW). Итак, когда несколько потоков используют один и тот же COM, вы имеете в виду, что наш прокси-сервер все еще отправляет параллельные вызовы, неуправляемый COM синхронизирует его?
3. Кроме того, когда вы говорите «… Все вызовы, которые вы выполняете из рабочих потоков, будут автоматически маршалироваться COM в поток, создавший COM-объект … «, я действительно не понимаю; мои рабочие потоки сами создают новые объекты из COM dll
4. @EagerToLearn: ваш клиент, похоже, неправильно понимает, как работает COM; они могут отправлять несколько вызовов из нескольких потоков (как и вы), но все эти вызовы сериализуются и вызываются по одному в потоке, в котором находится STA. Подсистема COM делает это автоматически за вас, и вы не можете обойти это (без серьезного ущерба для подсистемы).
5. Вы можете получить параллелизм, имея много процессов, каждый с одним потоком STA. Это может быть то, что делают клиенты VC и JAVA.
Ответ №1:
Если все, что у вас есть, это компонент COM, и он является компонентом STA, то вы ничего не можете сделать, чтобы экземпляр этого компонента вызывал службы одновременно.
Однако это не мешает вам создавать несколько экземпляров компонента и выполнять вызовы для нескольких экземпляров. С этой целью вы можете рассмотреть возможность использования пула объектов COM и получить свои экземпляры компонента таким образом.
Обратите внимание, что только потому, что служба, с которой взаимодействует компонент COM, способна обрабатывать запросы одновременно, является проблемой, которая полностью отделена от способности клиента обрабатывать вызовы к ней одновременно.
Предполагая, что вы можете получить доступ к коду, невозможно сказать, что потребуется для его запуска в MTA или free-threaded (последнее предпочтительнее); мы не знаем деталей реализации или состояния, которое сохраняется (или на что похож API).
Если все, что делает компонент, это отправляет запросы и обрабатывает ответы без сохранения состояния, тогда это должно быть довольно просто, это просто вопрос переключения квартиры.
Однако есть две причины, по которым компонент может быть STA:
1) Компонент имеет много состояний, и STA был способом убедиться, что состояние не было повреждено при одновременных вызовах; в этом случае ваша работа по созданию компонента MTA / free-threading будет сложной, так как вам придется все защищать, и даже тогда вы можетене получите никаких преимуществ из-за всех проверок параллелизма, которые вам, возможно, придется выполнить (хотя вы можете найти способ преобразовать код в .ЧИСТЫЙ код, таким образом, который легко потокобезопасен).
2) Компонент был написан на VB6 или языке, который не поддерживает компоненты MTA / free-threaded; в этом случае невозможно изменить модель квартиры, и вам придется либо иметь несколько экземпляров, либо выполнить преобразование в .СЕТЬ, которая является потокобезопасной.
Комментарии:
1. … не мешает вам создавать несколько экземпляров компонента… Что именно вы подразумеваете под компонентом? Вы видите, что COM dll имеет множество классов. Теперь основной поток моего приложения считывает все файлы запросов из папки, а затем помещает выполнение каждого запроса в новый поток из пула. Теперь каждый поток создает НОВЫЙ класс поиска, создает объект COMrequest, создает объект COMserver и отправляет запрос. Итак, каждый поток уже создает свой собственный набор COM-объектов.
2. @EagerToLearn: я имею в виду экземпляр класса.
3. Да, как я уже говорил выше, каждый поток создает свой собственный набор COM-объектов, но запросы, отправляемые этим потоком, не достигаются параллельно
Ответ №2:
Вероятно, вам потребуется создать несколько потоков STA, каждый со своим собственным циклом сообщений (*), и каждый со своим собственным экземпляром COM-объекта с общим потоком.
Вы можете установить базовое состояние потока, вызвав Thread .SetApartmentState.
(*) цикл обмена сообщениями необходим, если вам нужно маршалировать вызовы из другого потока.
Комментарии:
1. Я использую COM в первый раз, не могли бы вы рассказать мне простыми словами. Сторонняя библиотека DLL COM имеет много классов. Теперь я обрабатываю каждый запрос в отдельном потоке из пула. Каждый поток создает свой собственный набор объектов COMLookup, COMRequest, COMServer из COM DLL, но запросы, отправленные через метод submit на объекты COMServer из разных потоков, не достигают приложения COM server одновременно.
2. Согласитесь, вы должны иметь возможность создавать несколько потоков STA, и каждый из них может создавать один экземпляр этого COM-компонента и взаимодействовать с ним.
3. Вы не можете использовать системный пул потоков, потому что они не будут потоками STA. Создайте свои собственные потоки и установите для них значение STA.
4. Тот же поток, который создал COM-объект, должен вызывать методы для этого объекта. Не имея кода для просмотра, я предполагаю, что это не так.
5. @EagerToLearn, вызываете
SetApartmentState
ли вы каждый из своих потоков перед созданием его COM-объектов, чтобы убедиться, что они являются потоками STA?