Поддержка многопоточности COM

Работая с COM в первый раз, я получил эту dll COM, скажем ABCServer.dll, я создал RCW и добавил ссылку на него в свой проект. Теперь мое приложение создает несколько потоков, и каждый поток создает определенные классы из COM DLL и работает с ними. Но затем каждый поток ожидает, пока другой поток работает с определенным классом из COM dll.

Целью модификации моего приложения было включение многопоточности. Теперь, когда многопоточность происходит на моей стороне, COM вызывает последовательное соединение. Хотя каждый поток создает новые экземпляры, почему они ожидают обработки других?

3 ответа

Решение

В комментариях и ответах, опубликованных до сих пор, существует значительная путаница. STA или MTA является свойством потока. Но важно то, что требует компонент COM. Это объявлено в значении реестра ThreadingModel. Вы нашли "Квартира", очень распространенная обстановка. Это означает, что компонент не поддерживает многопоточность.

Это мало чем отличается от подавляющего большинства классов в.NET Framework, очень немногие являются поточно-ориентированными. Большая разница в том, что COM обеспечивает безопасность потоков. С классами.NET вы должны написать свой код, чтобы объекты класса использовались в поточно-ориентированном режиме. Это трудно понять, и хронический источник очень трудных для диагностики ошибок, но хорошо спроектированная блокировка позволяет обходить ограничения. С COM это невозможно, это всегда обеспечит безопасность потоков без вашей помощи. Даже если ты хочешь помочь.

Единственный способ добиться успеха - создать и использовать компонент COM только из одного потока. Этот поток должен быть инициализирован с помощью Thread.SetApartmentState(), чтобы выбрать STA. Что мешает COM создать собственный поток, чтобы найти безопасное убежище для компонента. И вы должны прокачать петлю сообщений, требование STA. Что может быть болезненным, и его можно избежать, если вы не пытаетесь использовать COM-компонент из другого потока, а сам компонент не зависит от наличия механизма сообщений. Что довольно распространено, кстати. Вы заметите, что он нужен, когда он перестает отвечать, как правило, не запускает событие, как ожидается. Вызывайте COM-объект только из одного потока, чтобы получить параллелизм с другими потоками, которые создают свой собственный объект. Это обычно не полезно или невозможно.

Если ваш COM-компонент помечен как STA (однопоточная квартира), то вы ничего не можете сделать, чтобы сделать его многопоточным; требование к компоненту состоит в том, что все вызовы к нему сериализуются в поток, в котором находится STA, и COM обрабатывает это автоматически для вас.

Тем не менее, если ваш компонент является компонентом STA (и кажется, что он есть), и вы не можете изменить его на многопоточный компонент квартиры (MTA) или, что еще лучше, на свободный поток (так что нет маршалинга между квартиры вообще) потому что а) он был написан на VB6, или б) это сторонний dll, тогда вам, возможно, будет лучше работать с какой-то моделью очереди.

По сути, все остальные ваши работы выполняются асинхронно, а затем создайте поток (или процесс, который вам решать), который будет принимать запросы для вызова этого компонента по одному, так быстро, как только сможет (учтите, вы можете создать экземпляр несколько экземпляров этого компонента в нескольких потоках, вы просто должны убедиться, что вы установили ApartmentState собственность на Thread класс дляApartmentState.STA), а затем опубликуйте события / обратные вызовы после завершения вызова и продолжите свою другую работу асинхронно.

По сути, это как две реализации производителя / потребителя: одна для отправки вызовов в компонент COM, а другая для отправки результатов, когда все будет сделано.

Если каждый из ваших потоков создает свой собственный экземпляр объекта модели квартиры, и каждый поток помечен для работы в STA, то каждый поток должен быть в своей отдельной STA, а экземпляры вашего COM-объекта должны работать в отдельных STA.

Другие ответы здесь предполагают, что все ваши экземпляры COM находятся в одной квартире. Если вы вызываете Thread.SetApartmentState(), чтобы убедиться, что каждый поток находится в STA до того, как он создаст экземпляры COM-объекта, тогда COM-объекты этого потока должны находиться в STA этого потока, который отделен от STA других потоков. Тогда вы не должны видеть сериализацию вызовов к объектам в разных STA.

Другие вопросы по тегам