Опасности потока C# MTA при создании COM-объекта STA

В настоящее время я смотрю на проблему, с которой мы сталкиваемся в службе Windows.Net Framework 2.0 (C#), у которой есть X потоков MTA, работающих с COM-компонентами. Каждый поток инициализирует свой собственный экземпляр компонента com. Компонент com не имеет элементов пользовательского интерфейса. Это просто бизнес-логика, которая взаимодействует с базой данных SQL-сервера и C# dll с интерфейсом com, который, в свою очередь, осуществляет сокет-связь и доступ к одной и той же базе данных SQL-сервера.

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

Будут ли проблемы параллелизма с моделью, описанной выше? Даже если каждый поток MTA создает свой собственный COM-объект STA?

редактировать

Проблема, с которой мы фактически сталкиваемся, заключается в том, что ссылка на объект не установлена ​​на экземпляр ошибки объекта в установщике строки соединения в следующем блоке кода. Это происходит внутри COM-объекта C#, который вызывается COM-объектом C++:

IDbConnection connection;

//Code omitted for brevity where connection is initialized

connection.ConnectionString = myConnectionString;

Тип исключения: System.NullReferenceException Сообщение: ссылка на объект не установлена ​​для экземпляра объекта. Данные: System.Collections.ListDictionaryInternal TargetSite: Void ConnectionString_Set(System.String) в System.Data.OracleClient.OracleConnection.ConnectionString_Set(String value) в System.Data.OracleClient.OracleConnection.set_ConnectionString(строковое значение)

1 ответ

Решение

Существует четыре основных "опасности" при звонках из MTA:

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

  • COM-объект не поддерживает прокси для маршалинга вызова. Это очень легко узнать, вызов завершится с E_NOINTERFACE.

  • клиентский программист не понимает, что он звонит из MTA и забывает маршалировать указатель интерфейса. COM не может предотвратить это при обращениях к внутреннему COM-серверу. Вы не можете сделать эту ошибку в программе.NET, CLR всегда будет маршалировать, но это легко сделать в других средах выполнения. В противном случае это вызывает общий гнев, связанный с выполнением небезопасных вызовов, работает, когда вы отлаживаете код, происходит сбой случайным образом в процессе производства и невозможен для отладки.

  • автор COM опубликовал свой компонент для совместимости с MTA, объявив его ThreadingModel как Оба или Бесплатно. Но на самом деле не достаточно тщательно протестировал свой код, писать потокобезопасный код, как известно, сложно. Особенно опасно в [ComVisible] .NET классах, потому что они автоматически регистрируются как Оба, и очень легко полностью забыть протестировать код на предмет этого обещания.

Ваш фрагмент слишком непостижим, чтобы сделать звонок, но возможный кандидат на 4-ую пулю. В противном случае не похоже, что какой-либо COM вообще вовлечен Такие провайдеры данных, как Oracle, обычно проходят бесплатную многопоточность и тщательно тестируются сотнями тысяч программистов.

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