Объекты, интерфейсы и апартаменты
Объекты, интерфейсы и апартаменты
Клиенты хотят вызывать методы объектов. Объекты просто хотят выставлять свои методы для клиентов. Тот факт, что объект может иметь ограничения на параллелизм (concurrency constraints), отличные от тех, которые привносятся клиентским апартаментом, является элементом реализации, о котором клиент не должен знать. Кроме того, если разработчик объекта сочтет нужным развернуть реализацию объекта только на малом количестве хост-машин, которое не содержит той хост-машины, где находится программа клиента, то это также является деталью реализации, о которой клиент не должен знать. В любом случае, однако, объект должен находиться в апартаменте, отличном от апартамента клиента.
С точки зрения программирования, членство в апартаменте является атрибутом интерфейсного указателя, а не атрибутом объекта. Когда интерфейсный указатель возвращается после вызова API-функции СОМ или после вызова метода, то поток, осуществивший вызов API-функции или метода, определяет, к какому апартаменту принадлежит результирующий интерфейсный указатель. Если вызов возвращает указатель на текущий объект, то объект сам расположен в апартаменте вызывающего потока. Часто объект не может находиться в вызывающем апартаменте: или потому, что объект уже существует и другом процессе или на другой хост-машине, или потому, что требования параллелизма, присущие этому объекту, несовместимы с клиентским апартаментом. В этих случаях клиент получает указатель на заместитель (proxy).
В СОМ заместителем называется объект, семантически идентичный объекту в другом апартаменте. По смыслу заместитель представляет собой точную копию объекта в другом апартаменте. Заместитель выставляет тот же набор интерфейсов, что и представляемый им объект, однако реализация заместителем каждого из интерфейсных методов просто переадресовывает вызовы на объект, обеспечивая тем самым то, что методы объекта всегда выполняются в его апартаменте. Любой интерфейсный указатель, получаемый клиентом от вызова API-функции или вызова метода, является легальным для всех потоков в апартаменте вызывающего объекта независимо от того, указывает он на объект или на заместитель.
Разработчики объектов выбирают типы апартаментов, в которых могут выполняться их объекты. В главе 6 будет рассмотрено, что внепроцессные серверы явно задают тип своих апартаментов посредством вызова CoInitializeEx с соответствующим параметром. Для внутрипроцессных серверов необходим другой подход, так как CoInitializeEx уже вызывалась клиентом во время создания объекта. Для того чтобы внутрипроцессные серверы могли контролировать тип своих апартаментов, в СОМ каждому CLSID разрешается задавать свою собственную потоковую модель (threading model), которая объявляется в локальном реестре с использованием переменной под названием ThreadingModel:
[HKCRCLSID {96556310-D779-11d0-8C4F-0080C73925BA}InprocServer32]
@="C: acer.dll"
ThreadingModel="Free"
Каждый CLSID в DLL может иметь индивидуальную ThreadingModel. Под Windows NT 4.0 СОМ допускает четыре возможных значения ThreadingModel для CLSID . Значение ThreadingModel="Both" указывает на то, что класс может выполняться как в МТА, так и в STA. Значение ThreadingModel="Free" указывает, что класс может выполняться только в МТА. Значение ThreadingModel="Apartment" указывает, что класс может выполняться только в STA. Отсутствие ThreadingModel означает, что класс может выполняться только в главном STA. Главный STA определяется как первый STA, который должен быть инициализирован в процессе.
Если апартамент клиента совместим с моделью организации поточной обработки идентификатора класса CLSID , то все запросы на внутрипроцессную активацию для этого CLSID будут обрабатывать объект непосредственно в апартаменте клиента. Это, безусловно, наиболее эффективный сценарий, так как не требуется никаких промежуточных заместителей[1]. Если же апартамент клиента несовместим с моделью организации поточной обработки, указанной в CLSID, то запросы на внутрипроцесспую активацию для таких CLSID будут приводить к скрытому созданию объекта в отдельном апартаменте, а клиенту будет возвращен заместитель. В случае, когда STA -клиенты активируют классы с ThreadingModel="Free", объект класса (и последующие его экземпляры) будут выполняться в МТА. В случае, когда MTA–клиенты активируют классы с ThreadingModel="Apartment", объект класса (и последующие его экземпляры) будут выполняться в STA , созданном СОМ. В случае, когда клиенты любого типа активируют классы на основе главного STA, объект класса (и последующие его экземпляры) будут выполняться в главном STA процесса. Если же клиент окажется потоком главного STA, то будет осуществлен прямой доступ к объекту. В противном случае клиенту будет возвращен заместитель. Если в процессе нет ни одного STA (то есть если ни один поток не вызвал CoInitiаlizeEx с флагом COINIT_APARTMENTTHREADED), тогда СОМ создаст новый STA с тем, чтобы он стал главным STA для процесса.
Разработчики классов, не предусматривающие модель организации поточной обработки для своих классов, могут большей частью игнорировать проблемы, связанные с потоками, так как доступ к их библиотекам DLL будет осуществляться только из одного потока, а именно из главного STA–потока. Те разработчики, которые предусматривают для своих классов поддержку любой явной модели организации поточной обработки, косвенно свидетельствуют, что каждый из множественных апартаментов в процессе (который может быть многопоточным) может содержать экземпляры класса. Поэтому разработчик должен защитить любые ресурсы, которые совместно используются более чем одним экземпляром класса, от параллельного доступа. Это означает, что все глобальные и статические переменные должны быть защищены с помощью соответствующего примитива синхронизации потоков. Для внутрипроцессного сервера СОМ глобальный счетчик блокировок, отслеживающий время жизни сервера, должен быть защищен с помощью InterlockedIncrement / InterlockedDecrement, как показано в главе 3. Любое другое специфическое для сервера состояние также должно быть защищено.
Разработчики, обозначающие свои классы ThreadingModel= «Apartment», указывают на то, что экземпляры этих классов могут быть доступны только из одного потока в течение всей жизни объекта. Следонательно, нет необходимости защищать режим экземпляра, а нужно защищать только режим, общий для нескольких экземпляров класса, о чем упоминалось ранее. Разработчики, обозначающие свои классы ThreadingModel="Free" или ThreadingModel="Both" устанавливают для экземпляров своего класса режим работы в МТА, что означает, что единовременно возможен доступ только к одному экземпляру класса. Поэтому разработчики должны защищать все ресурсы, используемые одним экземпляром, от параллельного доступа. Это относится не только к общим статическим переменным, но также к элементам данных экземпляра. Для объектов, расположенных в динамически распределяемой области памяти, это означает, что элемент данных, отвечающий за счетчик ссылок, должен быть защищён с помощью InterlockedIncrement/InterlockedDecrement, как было показано в главе 2. Любое другое состояние экземпляра класса также должно быть защищено.
На первый взгляд, совершенно не понятно, зачем существует ThreadingModel="Free", поскольку требования для работы в МТА выглядят как расширенный набор требований соответствия STA. Если разработчик объекта планирует рабочие потоки, которым необходим доступ к объекту, то очень полезно предотвратить создание объекта в каком-либо STA. Дело в том, что рабочие потоки не могут входить в STA, где живет объект, и поэтому вынуждены работать в другом апартаменте. Если класс обозначен ThreadingModel="Both" и запрос на активацию исходит от STA -потока, то объект будет существовать в STA. Это означает, что рабочие потоки (которые будут работать в МТА) должны обращаться к объекту через межапартаментные вызовы методов, значительно менее эффективные, нежели внутриапартаментные вызовы. Тем не менее, если класс помечен как ThreadingModel="Free", то любые запросы на активацию со стороны STA вызовут создание нового экземпляра в МТА, где любые рабочие потоки смогут иметь прямой доступ к объекту. Это означает, что при вызове клиентом, размещенным в STA, методов такого объекта, эффективность будет сниженной, в то время как рабочие потоки будут обрабатываться с большей эффективностью. Это является приемлемым компромиссом, если рабочие потоки будут обращаться к объекту чаще, чем действующий клиент из STA. Было бы весьма соблазнительно смягчить правила СОМ и записать, что не будет ошибкой прямо обращаться к некоторым объектам из более чем одного апартамента. Однако в общем случае это неверно, особенно для объектов, которые используют другие объекты для своей работы.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
6.2. Интерфейсы POSIX
6.2. Интерфейсы POSIX 6.2.1. Обязательные типы POSIX POSIX описывает некоторые определения типов в заголовочном файле <sys/types.h>, которые используются для многих аргументов и возвращаемых значений. Эти определения типов важны, потому что стандартные типы языка С могут быть разными
4.3. Интерфейсы
4.3. Интерфейсы Интерфейс (interface) служит для спецификации параметров модели, которые видимы извне без указания их внутренней структуры. В языке UML интерфейс является классификатором и характеризует только ограниченную часть поведения моделируемой сущности. Применительно
5.3. Интерфейсы .
5.3. Интерфейсы . Интерфейсы являются элементами диаграммы вариантов использования и были рассмотрены в главе 4. Однако при построении диаграммы классов отдельные интерфейсы могут уточняться и в этом случае для их изображения используется специальный графический символ
10.2. Интерфейсы
10.2. Интерфейсы Следующим элементом диаграммы компонентов являются интерфейсы. Последние уже неоднократно рассматривались ранее, поэтому здесь будут отмечены те их, особенности, которые характерны для представления на диаграммах компонентов. Напомним, что в общем
Объекты OS/400 и системные объекты MI
Объекты OS/400 и системные объекты MI Несколько типов объектов имеются и в OS/400, и в MI. Типы объектов OS/400 перечислены в таблице 5.1. Для сравнения, в таблице 5.2 приведены системные объекты MI. Помните, что в каждой новой версии AS/400 добавляются новые функции и даже новые объекты.
Интерфейсы пользователя
Интерфейсы пользователя Особый интерес вызывает будущий интерфейс пользователя вычислительной системы. Вчерашний графический интерфейс пользователя GUI (graphical user interface) быстро уступает дорогу новому сетевому интерфейсу пользователя NUI (network user interface). Несколько
Программные интерфейсы
Программные интерфейсы Программный интерфейс сокетов Вы уже познакомились с интерфейсом сокетов при обсуждении реализации межпроцессного взаимодействия в BSD UNIX. Поскольку сетевая поддержка впервые была разработана именно для BSD UNIX, интерфейс сокетов и сегодня
2.2 Интерфейсы IDE, EIDE и АТА
2.2 Интерфейсы IDE, EIDE и АТА Устройства с интерфейсом IDE являются самыми распространенными устройствами хранения данных в мире персональных компьютеров, особенно в потребительском сегменте рынка. Аббревиатура IDE расшифровывается как Integrated Drive Electronics (встроенный интерфейс
Глава 2. Интерфейсы
Глава 2. Интерфейсы void *pv = malloc(sizeof(int)); int *pi = (int*)pv; (*pi)++; free(pv); Аноним,1982 В предыдущей главе было показано несколько приемов программирования на C++, позволяющих разрабатывать двоичные компоненты повторного использования, которые со временем могут быть модернизированы. По
Интерфейсы и IDL
Интерфейсы и IDL Определения методов в IDL являются просто аннотированными аналогами С-функций. Определения интерфейсов в IDL требуют расширения по сравнению с С, так как С не имеет встроенной поддержки этого понятия. Определение интерфейса в IDL начинается с ключевого слова
Глава 5. Апартаменты
Глава 5. Апартаменты STDMETHODIMP CMyClass::MethodX(void) { EnterCr1t1calSect1on(&m_cs); if (TryToPerformX() == false) return E_UNEXPECTED: LeaveCriticalSect1on(&m_cs); return S_OK; } Аноним, 1996 В предыдущей главе обсуждались основы идентификации в СОМ и было формально определено, что именно отличает объекты СОМ от объектов памяти с
Объекты DataSet с множеством таблиц и объекты DataRelation
Объекты DataSet с множеством таблиц и объекты DataRelation До этого момента во всех примерах данной главы объекты DataSet содержали по одному объекту DataTable. Однако вся мощь несвязного уровня ADO.NET проявляется тогда, когда DataSet содержит множество объектов DataTable. В этом случае вы можете
Интерфейсы и упаковка
Интерфейсы и упаковка Herb Sutterr объяснил, что "интерфейс" класса (подразумевая, функциональные возможности, обеспечиваемые классом) включает также внешние функции, связанные с классом. Им также показано, что правила области видимости имен в C++ поддерживают эти изменения
7.3 Альтернативные Интерфейсы
7.3 Альтернативные Интерфейсы После того, как описаны средства языка, которые относяся к производным классам, обсуждение снова может вернуться к стоящим задачам. В классах, которые описываются в этом раздле, основополагающая идея состоит в том, что они однажды нписаны, а
Интерфейсы и проектирование ПО
Интерфейсы и проектирование ПО Архитектура системы должна основываться на содержании, а не на форме. Но проектирование сверху вниз стремится использовать в качестве основы для структуры самый поверхностный аспект системы - ее внешний интерфейс. Такой упор на внешний