Сущность технологии СОМ. Библиотека программиста

ОглавлениеДобавить в закладки К обложке

Маршалер свободной поточной обработки (FreeThreaded Marshaler)

Если в классе установлена опция ThreadingModel="Both" , то она показывает, что экземпляры класса, а также объект класса могут безопасно находиться в любых апартаментах: STA или МТА. В то же время, согласно правилам СОМ, любой данный экземпляр будет находиться только в одном апартаменте. Если бы разработчик объекта прошел все этапы проверки того, что объект может благополучно находиться в МТА, то в этом случае объекту вообще не нужно было бы заботиться об апартаментах. Одновременный доступ к подобному объекту мог бы быть не только для нескольких потоков внутри МТА, но также от потоков вне МТА (например, от потоков, выполняемых в STA). В то же время клиенты не могут знать, что такой доступ является безопасным для отдельно взятого объекта, поэтому любое совместное использование интерфейсного указателя в нескольких апартаментах должно быть установлено с использованием явной технологии маршалинга. Это означает, что доступ к внутрипроцессному объекту будет осуществляться через ORPC-вызовы, если только вызывающий объект не выполняется в том же самом апартаменте, где был создан объект.

В отличие от клиентов, объекты знают о своих отношениях с апартаментами, о своем параллелизме и реентерабельности. Объекты, удовлетворяющиеся ORPC-запросами при доступе из нескольких апартаментов одного и того же процесса, ведут себя так по умолчанию. А объект, которого не устраивает доступ ORPC, имеет возможность обойти это путем реализации специального маршалинга. Довольно просто использовать специальный маршалинг для обхода администратора заглушек и преобразования исходного указателя на объект в маршалированную объектную ссылку. При использовании этой технологии реализация специального заместителя могла бы просто считывать исходный указатель из маршалированной объектной ссылки и передавать его вызывающему объекту в импортирующем апартаменте. Клиентские потоки по-прежнему передавали бы интерфейсный указатель через границу апартамента с помощью явного или неявного вызова CoMarshalInterface / CoUnmarshalInterface. Однако объект мог бы договориться со специальным заместителем о том, чтобы просто передать исходный указатель нужному объекту. Хотя данная технология безупречно работает для внутрипроцессного маршалинга, она, к сожалению, не приводит к успеху в случае межпроцессного маршалинга. Но, к счастью, реализация объекта может просто обратиться к стандартному маршалеру за другим контекстом маршалинга, отличным от MSHCTX_INPROC.

Поскольку только что описанное поведение является полезным для большого класса объектов, в СОМ предусмотрена агрегируемая реализация IMarshal, выполняющая в точности то, что было описано. Эта реализация называется маршалером свободной поточной обработки (FreeThreaded Marshaler – FTM) и может быть осуществлена с помощью вызова API-функции CoCreateFreeThreadedMarshaler:

HRESULT CoCreateFreeThreadedMarshaler( [in] IUnknown *pUnkOuter, [out] IUnknown **ppUnkInner);

Класс, который желает использовать FTM, просто агрегирует экземпляр либо во время инициализации, либо по требованию при первом запросе QueryInterface об интерфейсе IMarshal . Следующий класс заранее обрабатывает FTM во время построения.

class Point : public IPoint {

LONG m_cRef; IUnknown *m_pUnkFTM;

long m_x; long m_y; Point(void) : m_cRef(0), m_x(0), m_y(0) {

HRESULT hr = CoCreateFreeThreadedMarshaler(this,&m_pUnkFTM);

assert(SUCCEEDED(hr)) ;

}

virtual ~Point(void) { m_pUnkFTM->Release(); }

};

Соответствующая реализация QueryInterface просто запросила бы интерфейс IMarshal из FTM:

STDMETHODIMP Point::QueryInterface(REFIID riid, void **ppv)

{ if (riid == IID_IUnknown || riid == IID_IPoint)

*ppv = static_cast<IPoint*>(this);

else if (riid == IID_IMarshal) return m_pUnkFTM->QueryInterface(riid, ppv);

else return (*ppv = 0), E_NOINTERFACE;

((IUnknown* )*ppv)->AddRef();

return S_OK;

}

Поскольку используется FTM, не понадобится никаких заместителей, как бы ни маршалировались через внутрипроцессные границы апартамента ссылки на объекты Point . Это применимо к явным вызовам CoMarshalInterface / CoUnmarshalInterface, а также в случаях, когда ссылки на объекты Point передаются как параметры метода на внутрипроцессные заместители объектов, не являющихся объектами Point.


Логин
Пароль
Запомнить меня