Включение
Не все классы способны к агрегированию. Для того чтобы выставить неагрегируемые классы как часть индивидуальности другого объекта, необходимо, чтобы внешние объекты явно передавали вызовы методов внутренним объектам. Эта технология СОМ часто называется включением (containment).
![Сущность технологии СОМ. Библиотека программиста fig4_9.jpg](https://litlife.club/books/47895/read/images/fig4_9.jpg)
Как показано на рис. 4.9, включение не требует никакого участия со стороны внутреннего объекта. В то же время требуется, чтобы во внешнем объекте производились реализации каждого интерфейса, выставляемого внутренним объектом. Эти внешние реализации просто передают клиентские запросы внутреннему объекту. Включение СОМ не требует никаких особых забот касательно правил идентификации СОМ, так как внутренний объект никогда не доступен клиенту впрямую и поэтому никогда непосредственно не внедряется в иерархию типов внешнего объекта. Хотя СОМ-включение входит в терминологию СОМ, оно не требует никаких особых программистских ухищрений. Фактически включаемый объект не может обнаружить, что внешний объект переадресовывает запросы его методов от действующего клиента.
Где мы находимся?
В данной главе обсуждались законы идентификации в СОМ. В этих законах определено, что означает быть объектом СОМ. Законы идентификации СОМ предоставляют разработчику объекта потрясающую гибкость при разделении реализации объекта. В качестве технологии для освобождения подсчета ссылок для каждого интерфейса была представлена композиция. Для сокращения размножения vptr, а также для более эффективного управления состоянием объекта были описаны отделяемые интерфейсы. Затем было показано агрегирование в качестве способа создания одной идентификационной единицы (identity ) из двух или более двоичных компонентов. Каждая из этих технологий позволяет более чем одному объекту выступать в качестве одной идентификационной единицы СОМ. Каждая технология имеет свои преимущества, и использование любой из них или всех вместе полностью скрыто от клиентов объекта.
Глава 5. Апартаменты
STDMETHODIMP CMyClass::MethodX(void) {
EnterCr1t1calSect1on(&m_cs);
if (TryToPerformX() == false)
return E_UNEXPECTED:
LeaveCriticalSect1on(&m_cs);
return S_OK; }
В предыдущей главе обсуждались основы идентификации в СОМ и было формально определено, что именно отличает объекты СОМ от объектов памяти с произвольной организацией. Были представлены правила IUnknown и способы использования этих правил для придания разработчику объектов максимальной гибкости. В данной главе уточняется понятие идентификации в СОМ с учетом базисных элементов (примитивов) операционной системы (например, потоков, процессов), а также распределенного доступа. Этот альянс базисных элементов системы и распределения формируют основу архитектуры удаленного доступа СОМ.
Снова интерфейс и реализация
Некоторые разработчики всесторонне используют многопоточные программные технологии и способны написать удивительно изощренный программный продукт с использованием примитивов синхронизации потоков, доступных из операционной системы. Другие разработчики больше сконцентрированы на решении вопросов, специфических для их области, и не утруждают себя написанием нудного потоко-безопасного кода. Третьи разработчики имеют особые ограничения по организации потоков, связанные с тем, что многие системы с управлением окнами (включая Windows) имеют очень строгие правила взаимодействия потоков и оконных примитивов. Еще один класс разработчиков может широко использовать старую библиотеку классов, которая неприязненно относится к потокам и не может допустить какого бы то ни было многопоточного обращения. У всех четырех типов разработчиков должна быть возможность использования объектов друг друга без перестраивания их потоковой стратегии, чтобы приспособиться ко всем возможным сценариям. Чтобы облегчить прозрачное использование объекта безотносительно к его осведомленности о потоках, СОМ рассматривает ограничения на параллелизм объектов как еще одну деталь реализации, о которой клиенту не нужно беспокоиться. Чтобы освободить клиента от ограничений параллелизма и реентерабельности (повторной входимости), в СОМ имеется весьма формальная абстракция, которая моделирует связь объектов с процессами и потоками. Эта абстракция носит название апартамент (apartment)[1] . Апартаменты определяют логическое группирование объектов, имеющих общий набор ограничений по параллелизму и реентерабельности. Каждый объект СОМ принадлежит к ровно одному апартаменту: один апартамент, однако, может быть общим для многих объектов. Апартамент, к которому относится объект, безоговорочно является частью идентификационной уникальности объекта.
Апартамент не является ни процессом, ни потоком; но в то же время апартаменты обладают некоторыми свойствами обоих этих понятий. Каждый процесс, использующий СОМ, имеет один апартамент или более; тем не менее, апартамент содержится ровно в одном процессе. Это означает, что каждый процесс, использующий СОМ, имеет как минимум одну группу объектов, которая удовлетворяет требованиям параллелизма и реентерабельности; однако два объекта, находящихся в одном и том же процессе, могут принадлежать к двум различным апартаментам и поэтому иметь разные ограничения по параллелизму и реентерабельности. Этот принцип позволяет библиотекам с совершенно различными понятиями о потоках мирно соучаствовать и одном общем процессе.
Поток одновременно выполняется в одном и только одном апартаменте. Для того чтобы поток мог использовать СОМ, он должен сначала войти в апартамент. Когда поток входит в апартамент, СОМ размещает информацию об апартаменте в локальной записи потока (TLS – thread local storage), и эта информация связана с потоком до тех пор, пока поток не покинет апартамент. СОМ обеспечивает доступ к объектам только для тех потоков, которые выполняются в апартаменте данного объекта. Это означает, что если поток выполняется в том же процессе, что и объект, то потоку может быть запрещено обращаться к объекту, даже если память, которую занимает объект, полностью видима и доступна. В СОМ определен HRESULT (RPC_E_WRONG_THREAD), который возвращают некоторые системные объекты при прямом обращении из других апартаментов. Объекты, определенные пользователем, также могут возвращать этот HRESULT; однако лишь немногие разработчики желают пройти столь долгий путь для обеспечения правильного использования своих объектов.
В версии СОМ под Windows NT 4.0 определяется два типа апартаментов: многопоточные апартаменты (МТА – multithreaded apartments) и однопоточные апартаменты (STA – singlethreaded apartments). В каждом процессе может быть не больше одного МТА; однако процесс может содержать несколько STA. Как следует из этих названий, в МТА может выполняться одновременно несколько потоков, а в STA – только один поток. Точнее, только один поток может когда-либо выполняться в данном STA; что означает не только то, что к объектам, находящимся в STA, никогда нельзя будет обратиться одновременно, но также и то, что только один определенный поток может когда-либо выполнять методы объекта. Эта привязка (affinity) к потоку позволяет разработчикам объекта надежно сохранять промежуточное состояние между вызовами метода в локальной памяти потока TLS (thread local storage), а также сохранять блокировки (locks), требующие поточной привязки (например, критические секции Win32 и семафоры (mutexes)).
1 Апартаменты являются более современным названием того, что в спецификации СОМ изначально именовалось контекстом исполнения (execution context).